From ab8ba71b018423779289c442f05a369e373dc41d Mon Sep 17 00:00:00 2001 From: John Naylor Date: Sat, 14 Feb 2026 11:41:34 +0700 Subject: [PATCH v8 2/4] Detect common prefix to avoid wasted work during radix sort Start radix sort at the most significant byte position that has more than one distinct byte in the input. This skips passes where radix sort would count the distinct bytes just to find only a single one, in which case there is nothing further to do for that pass. This can give a few percent speedup for integers that have some zero upper bytes, which is common for those that didn't arrive via abbreviation. Reviewed-by: Chengpeng Yan Discussion: https://postgr.es/m/CANWCAZYpGMDSSwAa18fOxJGXaPzVdyPsWpOkfCX32DWh3Qznzw@mail.gmail.com --- src/backend/utils/sort/tuplesort.c | 48 ++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c index 1fc440ea6ca..2203cfb725d 100644 --- a/src/backend/utils/sort/tuplesort.c +++ b/src/backend/utils/sort/tuplesort.c @@ -104,6 +104,7 @@ #include "commands/tablespace.h" #include "miscadmin.h" #include "pg_trace.h" +#include "port/pg_bitutils.h" #include "storage/shmem.h" #include "utils/guc.h" #include "utils/memutils.h" @@ -2909,28 +2910,65 @@ radix_sort_tuple(SortTuple *data, size_t n, Tuplesortstate *state) } else { + int common_prefix; + Datum ref_datum; + Datum common_upper_bits = 0; bool presorted = true; + Assert(not_null_count > 0); + ref_datum = not_null_start[0].datum1; + + /* compute the common prefix of all datums */ for (SortTuple *st = not_null_start + 1; st < not_null_start + not_null_count; st++) { - if (COMPARETUP(state, st - 1, st) > 0) - { + Datum this_datum = st->datum1; + + /* + * Accumulate bits that represent a difference from the reference + * datum. + */ + common_upper_bits |= ref_datum ^ this_datum; + + /* do a presorted check while we're at it */ + if (presorted && COMPARETUP(state, st - 1, st) > 0) presorted = false; - break; - } CHECK_FOR_INTERRUPTS(); } if (presorted) return; + else if (common_upper_bits == 0) + { + /* + * All NOT NULL tuples have the same datum, so we can skip radix + * sort. Sort using the tiebreak comparator if necessary. + */ + if (state->base.onlyKey == NULL) + { + qsort_tuple(not_null_start, + not_null_count, + state->base.comparetup_tiebreak, + state); + } + } else { + int diffpos; + + /* + * The upper bits of common_upper_bits are zero where all datums + * have the same bits. The byte position of the leftmost one bit + * is the byte where radix sort should start. + */ + diffpos = pg_leftmost_one_pos64(DatumGetUInt64(common_upper_bits)); + common_prefix = sizeof(Datum) - 1 - (diffpos / BITS_PER_BYTE); + radix_sort_recursive(not_null_start, not_null_count, - 0, + common_prefix, state); } } -- 2.53.0