mirror of
https://github.com/postgres/postgres.git
synced 2025-11-19 13:42:17 +03:00
Specialize tuplesort routines for different kinds of abbreviated keys
Previously, the specialized tuplesort routine inlined handling for reverse-sort and NULLs-ordering but called the datum comparator via a pointer in the SortSupport struct parameter. Testing has showed that we can get a useful performance gain by specializing datum comparison for the different representations of abbreviated keys -- signed and unsigned 64-bit integers and signed 32-bit integers. Almost all abbreviatable data types will benefit -- the only exception for now is numeric, since the datum comparison is more complex. The performance gain depends on data type and input distribution, but often falls in the range of 10-20% faster. Thomas Munro Reviewed by Peter Geoghegan, review and performance testing by me Discussion: https://www.postgresql.org/message-id/CA%2BhUKGKKYttZZk-JMRQSVak%3DCXSJ5fiwtirFf%3Dn%3DPAbumvn1Ww%40mail.gmail.com
This commit is contained in:
@@ -669,14 +669,101 @@ static void free_sort_tuple(Tuplesortstate *state, SortTuple *stup);
|
||||
static void tuplesort_free(Tuplesortstate *state);
|
||||
static void tuplesort_updatemax(Tuplesortstate *state);
|
||||
|
||||
/*
|
||||
* Specialized comparators that we can inline into specialized sorts. The goal
|
||||
* is to try to sort two tuples without having to follow the pointers to the
|
||||
* comparator or the tuple.
|
||||
*
|
||||
* XXX: For now, these fall back to comparator functions that will compare the
|
||||
* leading datum a second time.
|
||||
*
|
||||
* XXX: For now, there is no specialization for cases where datum1 is
|
||||
* authoritative and we don't even need to fall back to a callback at all (that
|
||||
* would be true for types like int4/int8/timestamp/date, but not true for
|
||||
* abbreviations of text or multi-key sorts. There could be! Is it worth it?
|
||||
*/
|
||||
|
||||
/* Used if first key's comparator is ssup_datum_unsigned_compare */
|
||||
static pg_attribute_always_inline int
|
||||
qsort_tuple_unsigned_compare(SortTuple *a, SortTuple *b, Tuplesortstate *state)
|
||||
{
|
||||
int compare;
|
||||
|
||||
compare = ApplyUnsignedSortComparator(a->datum1, a->isnull1,
|
||||
b->datum1, b->isnull1,
|
||||
&state->sortKeys[0]);
|
||||
if (compare != 0)
|
||||
return compare;
|
||||
|
||||
return state->comparetup(a, b, state);
|
||||
}
|
||||
|
||||
/* Used if first key's comparator is ssup_datum_signed_compare */
|
||||
static pg_attribute_always_inline int
|
||||
qsort_tuple_signed_compare(SortTuple *a, SortTuple *b, Tuplesortstate *state)
|
||||
{
|
||||
int compare;
|
||||
|
||||
compare = ApplySignedSortComparator(a->datum1, a->isnull1,
|
||||
b->datum1, b->isnull1,
|
||||
&state->sortKeys[0]);
|
||||
if (compare != 0)
|
||||
return compare;
|
||||
|
||||
return state->comparetup(a, b, state);
|
||||
}
|
||||
|
||||
/* Used if first key's comparator is ssup_datum_int32_compare */
|
||||
static pg_attribute_always_inline int
|
||||
qsort_tuple_int32_compare(SortTuple *a, SortTuple *b, Tuplesortstate *state)
|
||||
{
|
||||
int compare;
|
||||
|
||||
compare = ApplyInt32SortComparator(a->datum1, a->isnull1,
|
||||
b->datum1, b->isnull1,
|
||||
&state->sortKeys[0]);
|
||||
if (compare != 0)
|
||||
return compare;
|
||||
|
||||
return state->comparetup(a, b, state);
|
||||
}
|
||||
|
||||
/*
|
||||
* Special versions of qsort just for SortTuple objects. qsort_tuple() sorts
|
||||
* any variant of SortTuples, using the appropriate comparetup function.
|
||||
* qsort_ssup() is specialized for the case where the comparetup function
|
||||
* reduces to ApplySortComparator(), that is single-key MinimalTuple sorts
|
||||
* and Datum sorts.
|
||||
* and Datum sorts. qsort_tuple_{unsigned,signed,int32} are specialized for
|
||||
* common comparison functions on pass-by-value leading datums.
|
||||
*/
|
||||
|
||||
#define ST_SORT qsort_tuple_unsigned
|
||||
#define ST_ELEMENT_TYPE SortTuple
|
||||
#define ST_COMPARE(a, b, state) qsort_tuple_unsigned_compare(a, b, state)
|
||||
#define ST_COMPARE_ARG_TYPE Tuplesortstate
|
||||
#define ST_CHECK_FOR_INTERRUPTS
|
||||
#define ST_SCOPE static
|
||||
#define ST_DEFINE
|
||||
#include "lib/sort_template.h"
|
||||
|
||||
#define ST_SORT qsort_tuple_signed
|
||||
#define ST_ELEMENT_TYPE SortTuple
|
||||
#define ST_COMPARE(a, b, state) qsort_tuple_signed_compare(a, b, state)
|
||||
#define ST_COMPARE_ARG_TYPE Tuplesortstate
|
||||
#define ST_CHECK_FOR_INTERRUPTS
|
||||
#define ST_SCOPE static
|
||||
#define ST_DEFINE
|
||||
#include "lib/sort_template.h"
|
||||
|
||||
#define ST_SORT qsort_tuple_int32
|
||||
#define ST_ELEMENT_TYPE SortTuple
|
||||
#define ST_COMPARE(a, b, state) qsort_tuple_int32_compare(a, b, state)
|
||||
#define ST_COMPARE_ARG_TYPE Tuplesortstate
|
||||
#define ST_CHECK_FOR_INTERRUPTS
|
||||
#define ST_SCOPE static
|
||||
#define ST_DEFINE
|
||||
#include "lib/sort_template.h"
|
||||
|
||||
#define ST_SORT qsort_tuple
|
||||
#define ST_ELEMENT_TYPE SortTuple
|
||||
#define ST_COMPARE_RUNTIME_POINTER
|
||||
@@ -3506,15 +3593,40 @@ tuplesort_sort_memtuples(Tuplesortstate *state)
|
||||
|
||||
if (state->memtupcount > 1)
|
||||
{
|
||||
/* Do we have a specialization for the leading column's comparator? */
|
||||
if (state->sortKeys &&
|
||||
state->sortKeys[0].comparator == ssup_datum_unsigned_cmp)
|
||||
{
|
||||
elog(DEBUG1, "qsort_tuple_unsigned");
|
||||
qsort_tuple_unsigned(state->memtuples, state->memtupcount, state);
|
||||
}
|
||||
else if (state->sortKeys &&
|
||||
state->sortKeys[0].comparator == ssup_datum_signed_cmp)
|
||||
{
|
||||
elog(DEBUG1, "qsort_tuple_signed");
|
||||
qsort_tuple_signed(state->memtuples, state->memtupcount, state);
|
||||
}
|
||||
else if (state->sortKeys &&
|
||||
state->sortKeys[0].comparator == ssup_datum_int32_cmp)
|
||||
{
|
||||
elog(DEBUG1, "qsort_tuple_int32");
|
||||
qsort_tuple_int32(state->memtuples, state->memtupcount, state);
|
||||
}
|
||||
/* Can we use the single-key sort function? */
|
||||
if (state->onlyKey != NULL)
|
||||
else if (state->onlyKey != NULL)
|
||||
{
|
||||
elog(DEBUG1, "qsort_ssup");
|
||||
qsort_ssup(state->memtuples, state->memtupcount,
|
||||
state->onlyKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
elog(DEBUG1, "qsort_tuple");
|
||||
qsort_tuple(state->memtuples,
|
||||
state->memtupcount,
|
||||
state->comparetup,
|
||||
state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4700,3 +4812,47 @@ free_sort_tuple(Tuplesortstate *state, SortTuple *stup)
|
||||
stup->tuple = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
ssup_datum_unsigned_cmp(Datum x, Datum y, SortSupport ssup)
|
||||
{
|
||||
if (x < y)
|
||||
return -1;
|
||||
else if (x > y)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ssup_datum_signed_cmp(Datum x, Datum y, SortSupport ssup)
|
||||
{
|
||||
#if SIZEOF_DATUM == 8
|
||||
int64 xx = (int64) x;
|
||||
int64 yy = (int64) y;
|
||||
#else
|
||||
int32 xx = (int32) x;
|
||||
int32 yy = (int32) y;
|
||||
#endif
|
||||
|
||||
if (xx < yy)
|
||||
return -1;
|
||||
else if (xx > yy)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ssup_datum_int32_cmp(Datum x, Datum y, SortSupport ssup)
|
||||
{
|
||||
int32 xx = (int32) x;
|
||||
int32 yy = (int32) y;
|
||||
|
||||
if (xx < yy)
|
||||
return -1;
|
||||
else if (xx > yy)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user