mirror of
https://github.com/postgres/postgres.git
synced 2025-11-10 17:42:29 +03:00
Speed up in-memory tuplesorting.
Per recent work by Peter Geoghegan, it's significantly faster to tuplesort on a single sortkey if ApplySortComparator is inlined into quicksort rather reached via a function pointer. It's also faster in general to have a version of quicksort which is specialized for sorting SortTuple objects rather than objects of arbitrary size and type. This requires a couple of additional copies of the quicksort logic, which in this patch are generate using a Perl script. There might be some benefit in adding further specializations here too, but thus far it's not clear that those gains are worth their weight in code footprint.
This commit is contained in:
@@ -195,6 +195,9 @@ typedef enum
|
||||
#define TAPE_BUFFER_OVERHEAD (BLCKSZ * 3)
|
||||
#define MERGE_BUFFER_SIZE (BLCKSZ * 32)
|
||||
|
||||
typedef int (*SortTupleComparator) (const SortTuple *a, const SortTuple *b,
|
||||
Tuplesortstate *state);
|
||||
|
||||
/*
|
||||
* Private state of a Tuplesort operation.
|
||||
*/
|
||||
@@ -223,8 +226,7 @@ struct Tuplesortstate
|
||||
* <0, 0, >0 according as a<b, a=b, a>b. The API must match
|
||||
* qsort_arg_comparator.
|
||||
*/
|
||||
int (*comparetup) (const SortTuple *a, const SortTuple *b,
|
||||
Tuplesortstate *state);
|
||||
SortTupleComparator comparetup;
|
||||
|
||||
/*
|
||||
* Function to copy a supplied input tuple into palloc'd space and set up
|
||||
@@ -363,12 +365,14 @@ struct Tuplesortstate
|
||||
/* These are specific to the index_hash subcase: */
|
||||
uint32 hash_mask; /* mask for sortable part of hash code */
|
||||
|
||||
/* This is initialized when, and only when, there's just one key. */
|
||||
SortSupport onlyKey;
|
||||
|
||||
/*
|
||||
* These variables are specific to the Datum case; they are set by
|
||||
* tuplesort_begin_datum and used only by the DatumTuple routines.
|
||||
*/
|
||||
Oid datumType;
|
||||
SortSupport datumKey;
|
||||
/* we need typelen and byval in order to know how to copy the Datums. */
|
||||
int datumTypeLen;
|
||||
bool datumTypeByVal;
|
||||
@@ -492,6 +496,11 @@ static void readtup_datum(Tuplesortstate *state, SortTuple *stup,
|
||||
static void reversedirection_datum(Tuplesortstate *state);
|
||||
static void free_sort_tuple(Tuplesortstate *state, SortTuple *stup);
|
||||
|
||||
/*
|
||||
* Special version of qsort, just for SortTuple objects.
|
||||
*/
|
||||
#include "qsort_tuple.c"
|
||||
|
||||
|
||||
/*
|
||||
* tuplesort_begin_xxx
|
||||
@@ -631,6 +640,9 @@ tuplesort_begin_heap(TupleDesc tupDesc,
|
||||
PrepareSortSupportFromOrderingOp(sortOperators[i], sortKey);
|
||||
}
|
||||
|
||||
if (nkeys == 1)
|
||||
state->onlyKey = state->sortKeys;
|
||||
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
|
||||
return state;
|
||||
@@ -809,13 +821,13 @@ tuplesort_begin_datum(Oid datumType, Oid sortOperator, Oid sortCollation,
|
||||
state->datumType = datumType;
|
||||
|
||||
/* Prepare SortSupport data */
|
||||
state->datumKey = (SortSupport) palloc0(sizeof(SortSupportData));
|
||||
state->onlyKey = (SortSupport) palloc0(sizeof(SortSupportData));
|
||||
|
||||
state->datumKey->ssup_cxt = CurrentMemoryContext;
|
||||
state->datumKey->ssup_collation = sortCollation;
|
||||
state->datumKey->ssup_nulls_first = nullsFirstFlag;
|
||||
state->onlyKey->ssup_cxt = CurrentMemoryContext;
|
||||
state->onlyKey->ssup_collation = sortCollation;
|
||||
state->onlyKey->ssup_nulls_first = nullsFirstFlag;
|
||||
|
||||
PrepareSortSupportFromOrderingOp(sortOperator, state->datumKey);
|
||||
PrepareSortSupportFromOrderingOp(sortOperator, state->onlyKey);
|
||||
|
||||
/* lookup necessary attributes of the datum type */
|
||||
get_typlenbyval(datumType, &typlen, &typbyval);
|
||||
@@ -1222,11 +1234,16 @@ tuplesort_performsort(Tuplesortstate *state)
|
||||
* amount of memory. Just qsort 'em and we're done.
|
||||
*/
|
||||
if (state->memtupcount > 1)
|
||||
qsort_arg((void *) state->memtuples,
|
||||
state->memtupcount,
|
||||
sizeof(SortTuple),
|
||||
(qsort_arg_comparator) state->comparetup,
|
||||
(void *) state);
|
||||
{
|
||||
if (state->onlyKey != NULL)
|
||||
qsort_ssup(state->memtuples, state->memtupcount,
|
||||
state->onlyKey);
|
||||
else
|
||||
qsort_tuple(state->memtuples,
|
||||
state->memtupcount,
|
||||
state->comparetup,
|
||||
state);
|
||||
}
|
||||
state->current = 0;
|
||||
state->eof_reached = false;
|
||||
state->markpos_offset = 0;
|
||||
@@ -2660,9 +2677,6 @@ comparetup_heap(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
|
||||
int nkey;
|
||||
int32 compare;
|
||||
|
||||
/* Allow interrupting long sorts */
|
||||
CHECK_FOR_INTERRUPTS();
|
||||
|
||||
/* Compare the leading sort key */
|
||||
compare = ApplySortComparator(a->datum1, a->isnull1,
|
||||
b->datum1, b->isnull1,
|
||||
@@ -2804,9 +2818,6 @@ comparetup_cluster(const SortTuple *a, const SortTuple *b,
|
||||
int nkey;
|
||||
int32 compare;
|
||||
|
||||
/* Allow interrupting long sorts */
|
||||
CHECK_FOR_INTERRUPTS();
|
||||
|
||||
/* Compare the leading sort key, if it's simple */
|
||||
if (state->indexInfo->ii_KeyAttrNumbers[0] != 0)
|
||||
{
|
||||
@@ -2995,9 +3006,6 @@ comparetup_index_btree(const SortTuple *a, const SortTuple *b,
|
||||
int nkey;
|
||||
int32 compare;
|
||||
|
||||
/* Allow interrupting long sorts */
|
||||
CHECK_FOR_INTERRUPTS();
|
||||
|
||||
/* Compare the leading sort key */
|
||||
compare = inlineApplySortFunction(&scanKey->sk_func, scanKey->sk_flags,
|
||||
scanKey->sk_collation,
|
||||
@@ -3102,9 +3110,6 @@ comparetup_index_hash(const SortTuple *a, const SortTuple *b,
|
||||
IndexTuple tuple1;
|
||||
IndexTuple tuple2;
|
||||
|
||||
/* Allow interrupting long sorts */
|
||||
CHECK_FOR_INTERRUPTS();
|
||||
|
||||
/*
|
||||
* Fetch hash keys and mask off bits we don't want to sort by. We know
|
||||
* that the first column of the index tuple is the hash key.
|
||||
@@ -3231,12 +3236,9 @@ reversedirection_index_hash(Tuplesortstate *state)
|
||||
static int
|
||||
comparetup_datum(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
|
||||
{
|
||||
/* Allow interrupting long sorts */
|
||||
CHECK_FOR_INTERRUPTS();
|
||||
|
||||
return ApplySortComparator(a->datum1, a->isnull1,
|
||||
b->datum1, b->isnull1,
|
||||
state->datumKey);
|
||||
/* Not currently needed */
|
||||
elog(ERROR, "comparetup_datum() should not be called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -3328,8 +3330,8 @@ readtup_datum(Tuplesortstate *state, SortTuple *stup,
|
||||
static void
|
||||
reversedirection_datum(Tuplesortstate *state)
|
||||
{
|
||||
state->datumKey->ssup_reverse = !state->datumKey->ssup_reverse;
|
||||
state->datumKey->ssup_nulls_first = !state->datumKey->ssup_nulls_first;
|
||||
state->onlyKey->ssup_reverse = !state->onlyKey->ssup_reverse;
|
||||
state->onlyKey->ssup_nulls_first = !state->onlyKey->ssup_nulls_first;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user