Skip to content

Commit 6974924

Browse files
committed
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
1 parent db086de commit 6974924

File tree

10 files changed

+308
-132
lines changed

10 files changed

+308
-132
lines changed

src/backend/access/gist/gistproc.c

+1-17
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ static uint64 part_bits32_by2(uint32 x);
3737
static uint32 ieee_float32_to_uint32(float f);
3838
static int gist_bbox_zorder_cmp(Datum a, Datum b, SortSupport ssup);
3939
static Datum gist_bbox_zorder_abbrev_convert(Datum original, SortSupport ssup);
40-
static int gist_bbox_zorder_cmp_abbrev(Datum z1, Datum z2, SortSupport ssup);
4140
static bool gist_bbox_zorder_abbrev_abort(int memtupcount, SortSupport ssup);
4241

4342

@@ -1726,21 +1725,6 @@ gist_bbox_zorder_abbrev_convert(Datum original, SortSupport ssup)
17261725
#endif
17271726
}
17281727

1729-
static int
1730-
gist_bbox_zorder_cmp_abbrev(Datum z1, Datum z2, SortSupport ssup)
1731-
{
1732-
/*
1733-
* Compare the pre-computed Z-orders as unsigned integers. Datum is a
1734-
* typedef for 'uintptr_t', so no casting is required.
1735-
*/
1736-
if (z1 > z2)
1737-
return 1;
1738-
else if (z1 < z2)
1739-
return -1;
1740-
else
1741-
return 0;
1742-
}
1743-
17441728
/*
17451729
* We never consider aborting the abbreviation.
17461730
*
@@ -1764,7 +1748,7 @@ gist_point_sortsupport(PG_FUNCTION_ARGS)
17641748

17651749
if (ssup->abbreviate)
17661750
{
1767-
ssup->comparator = gist_bbox_zorder_cmp_abbrev;
1751+
ssup->comparator = ssup_datum_unsigned_cmp;
17681752
ssup->abbrev_converter = gist_bbox_zorder_abbrev_convert;
17691753
ssup->abbrev_abort = gist_bbox_zorder_abbrev_abort;
17701754
ssup->abbrev_full_comparator = gist_bbox_zorder_cmp;

src/backend/access/nbtree/nbtcompare.c

+7-15
Original file line numberDiff line numberDiff line change
@@ -119,26 +119,12 @@ btint4cmp(PG_FUNCTION_ARGS)
119119
PG_RETURN_INT32(A_LESS_THAN_B);
120120
}
121121

122-
static int
123-
btint4fastcmp(Datum x, Datum y, SortSupport ssup)
124-
{
125-
int32 a = DatumGetInt32(x);
126-
int32 b = DatumGetInt32(y);
127-
128-
if (a > b)
129-
return A_GREATER_THAN_B;
130-
else if (a == b)
131-
return 0;
132-
else
133-
return A_LESS_THAN_B;
134-
}
135-
136122
Datum
137123
btint4sortsupport(PG_FUNCTION_ARGS)
138124
{
139125
SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
140126

141-
ssup->comparator = btint4fastcmp;
127+
ssup->comparator = ssup_datum_int32_cmp;
142128
PG_RETURN_VOID();
143129
}
144130

@@ -156,6 +142,7 @@ btint8cmp(PG_FUNCTION_ARGS)
156142
PG_RETURN_INT32(A_LESS_THAN_B);
157143
}
158144

145+
#ifndef USE_FLOAT8_BYVAL
159146
static int
160147
btint8fastcmp(Datum x, Datum y, SortSupport ssup)
161148
{
@@ -169,13 +156,18 @@ btint8fastcmp(Datum x, Datum y, SortSupport ssup)
169156
else
170157
return A_LESS_THAN_B;
171158
}
159+
#endif
172160

173161
Datum
174162
btint8sortsupport(PG_FUNCTION_ARGS)
175163
{
176164
SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
177165

166+
#ifdef USE_FLOAT8_BYVAL
167+
ssup->comparator = ssup_datum_signed_cmp;
168+
#else
178169
ssup->comparator = btint8fastcmp;
170+
#endif
179171
PG_RETURN_VOID();
180172
}
181173

src/backend/utils/adt/date.c

+1-14
Original file line numberDiff line numberDiff line change
@@ -439,25 +439,12 @@ date_cmp(PG_FUNCTION_ARGS)
439439
PG_RETURN_INT32(0);
440440
}
441441

442-
static int
443-
date_fastcmp(Datum x, Datum y, SortSupport ssup)
444-
{
445-
DateADT a = DatumGetDateADT(x);
446-
DateADT b = DatumGetDateADT(y);
447-
448-
if (a < b)
449-
return -1;
450-
else if (a > b)
451-
return 1;
452-
return 0;
453-
}
454-
455442
Datum
456443
date_sortsupport(PG_FUNCTION_ARGS)
457444
{
458445
SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
459446

460-
ssup->comparator = date_fastcmp;
447+
ssup->comparator = ssup_datum_int32_cmp;
461448
PG_RETURN_VOID();
462449
}
463450

src/backend/utils/adt/mac.c

+3-20
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ typedef struct
4444

4545
static int macaddr_cmp_internal(macaddr *a1, macaddr *a2);
4646
static int macaddr_fast_cmp(Datum x, Datum y, SortSupport ssup);
47-
static int macaddr_cmp_abbrev(Datum x, Datum y, SortSupport ssup);
4847
static bool macaddr_abbrev_abort(int memtupcount, SortSupport ssup);
4948
static Datum macaddr_abbrev_convert(Datum original, SortSupport ssup);
5049

@@ -381,7 +380,7 @@ macaddr_sortsupport(PG_FUNCTION_ARGS)
381380

382381
ssup->ssup_extra = uss;
383382

384-
ssup->comparator = macaddr_cmp_abbrev;
383+
ssup->comparator = ssup_datum_unsigned_cmp;
385384
ssup->abbrev_converter = macaddr_abbrev_convert;
386385
ssup->abbrev_abort = macaddr_abbrev_abort;
387386
ssup->abbrev_full_comparator = macaddr_fast_cmp;
@@ -405,22 +404,6 @@ macaddr_fast_cmp(Datum x, Datum y, SortSupport ssup)
405404
return macaddr_cmp_internal(arg1, arg2);
406405
}
407406

408-
/*
409-
* SortSupport abbreviated key comparison function. Compares two MAC addresses
410-
* quickly by treating them like integers, and without having to go to the
411-
* heap.
412-
*/
413-
static int
414-
macaddr_cmp_abbrev(Datum x, Datum y, SortSupport ssup)
415-
{
416-
if (x > y)
417-
return 1;
418-
else if (x == y)
419-
return 0;
420-
else
421-
return -1;
422-
}
423-
424407
/*
425408
* Callback for estimating effectiveness of abbreviated key optimization.
426409
*
@@ -537,8 +520,8 @@ macaddr_abbrev_convert(Datum original, SortSupport ssup)
537520
/*
538521
* Byteswap on little-endian machines.
539522
*
540-
* This is needed so that macaddr_cmp_abbrev() (an unsigned integer 3-way
541-
* comparator) works correctly on all platforms. Without this, the
523+
* This is needed so that ssup_datum_unsigned_cmp() (an unsigned integer
524+
* 3-way comparator) works correctly on all platforms. Without this, the
542525
* comparator would have to call memcmp() with a pair of pointers to the
543526
* first byte of each abbreviated key, which is slower.
544527
*/

src/backend/utils/adt/network.c

+1-16
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ typedef struct
5353

5454
static int32 network_cmp_internal(inet *a1, inet *a2);
5555
static int network_fast_cmp(Datum x, Datum y, SortSupport ssup);
56-
static int network_cmp_abbrev(Datum x, Datum y, SortSupport ssup);
5756
static bool network_abbrev_abort(int memtupcount, SortSupport ssup);
5857
static Datum network_abbrev_convert(Datum original, SortSupport ssup);
5958
static List *match_network_function(Node *leftop,
@@ -456,7 +455,7 @@ network_sortsupport(PG_FUNCTION_ARGS)
456455

457456
ssup->ssup_extra = uss;
458457

459-
ssup->comparator = network_cmp_abbrev;
458+
ssup->comparator = ssup_datum_unsigned_cmp;
460459
ssup->abbrev_converter = network_abbrev_convert;
461460
ssup->abbrev_abort = network_abbrev_abort;
462461
ssup->abbrev_full_comparator = network_fast_cmp;
@@ -479,20 +478,6 @@ network_fast_cmp(Datum x, Datum y, SortSupport ssup)
479478
return network_cmp_internal(arg1, arg2);
480479
}
481480

482-
/*
483-
* Abbreviated key comparison func
484-
*/
485-
static int
486-
network_cmp_abbrev(Datum x, Datum y, SortSupport ssup)
487-
{
488-
if (x > y)
489-
return 1;
490-
else if (x == y)
491-
return 0;
492-
else
493-
return -1;
494-
}
495-
496481
/*
497482
* Callback for estimating effectiveness of abbreviated key optimization.
498483
*

src/backend/utils/adt/timestamp.c

+11
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "utils/datetime.h"
3838
#include "utils/float.h"
3939
#include "utils/numeric.h"
40+
#include "utils/sortsupport.h"
4041

4142
/*
4243
* gcc's -ffast-math switch breaks routines that expect exact results from
@@ -2155,6 +2156,7 @@ timestamp_cmp(PG_FUNCTION_ARGS)
21552156
PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
21562157
}
21572158

2159+
#ifndef USE_FLOAT8_BYVAL
21582160
/* note: this is used for timestamptz also */
21592161
static int
21602162
timestamp_fastcmp(Datum x, Datum y, SortSupport ssup)
@@ -2164,13 +2166,22 @@ timestamp_fastcmp(Datum x, Datum y, SortSupport ssup)
21642166

21652167
return timestamp_cmp_internal(a, b);
21662168
}
2169+
#endif
21672170

21682171
Datum
21692172
timestamp_sortsupport(PG_FUNCTION_ARGS)
21702173
{
21712174
SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
21722175

2176+
#ifdef USE_FLOAT8_BYVAL
2177+
/*
2178+
* If this build has pass-by-value timestamps, then we can use a standard
2179+
* comparator function.
2180+
*/
2181+
ssup->comparator = ssup_datum_signed_cmp;
2182+
#else
21732183
ssup->comparator = timestamp_fastcmp;
2184+
#endif
21742185
PG_RETURN_VOID();
21752186
}
21762187

src/backend/utils/adt/uuid.c

+5-20
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ typedef struct
3434
static void string_to_uuid(const char *source, pg_uuid_t *uuid);
3535
static int uuid_internal_cmp(const pg_uuid_t *arg1, const pg_uuid_t *arg2);
3636
static int uuid_fast_cmp(Datum x, Datum y, SortSupport ssup);
37-
static int uuid_cmp_abbrev(Datum x, Datum y, SortSupport ssup);
3837
static bool uuid_abbrev_abort(int memtupcount, SortSupport ssup);
3938
static Datum uuid_abbrev_convert(Datum original, SortSupport ssup);
4039

@@ -255,7 +254,7 @@ uuid_sortsupport(PG_FUNCTION_ARGS)
255254

256255
ssup->ssup_extra = uss;
257256

258-
ssup->comparator = uuid_cmp_abbrev;
257+
ssup->comparator = ssup_datum_unsigned_cmp;
259258
ssup->abbrev_converter = uuid_abbrev_convert;
260259
ssup->abbrev_abort = uuid_abbrev_abort;
261260
ssup->abbrev_full_comparator = uuid_fast_cmp;
@@ -278,20 +277,6 @@ uuid_fast_cmp(Datum x, Datum y, SortSupport ssup)
278277
return uuid_internal_cmp(arg1, arg2);
279278
}
280279

281-
/*
282-
* Abbreviated key comparison func
283-
*/
284-
static int
285-
uuid_cmp_abbrev(Datum x, Datum y, SortSupport ssup)
286-
{
287-
if (x > y)
288-
return 1;
289-
else if (x == y)
290-
return 0;
291-
else
292-
return -1;
293-
}
294-
295280
/*
296281
* Callback for estimating effectiveness of abbreviated key optimization.
297282
*
@@ -390,10 +375,10 @@ uuid_abbrev_convert(Datum original, SortSupport ssup)
390375
/*
391376
* Byteswap on little-endian machines.
392377
*
393-
* This is needed so that uuid_cmp_abbrev() (an unsigned integer 3-way
394-
* comparator) works correctly on all platforms. If we didn't do this,
395-
* the comparator would have to call memcmp() with a pair of pointers to
396-
* the first byte of each abbreviated key, which is slower.
378+
* This is needed so that ssup_datum_unsigned_cmp() (an unsigned integer
379+
* 3-way comparator) works correctly on all platforms. If we didn't do
380+
* this, the comparator would have to call memcmp() with a pair of pointers
381+
* to the first byte of each abbreviated key, which is slower.
397382
*/
398383
res = DatumBigEndianToNative(res);
399384

src/backend/utils/adt/varlena.c

+6-28
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,6 @@ static int namefastcmp_c(Datum x, Datum y, SortSupport ssup);
126126
static int varlenafastcmp_locale(Datum x, Datum y, SortSupport ssup);
127127
static int namefastcmp_locale(Datum x, Datum y, SortSupport ssup);
128128
static int varstrfastcmp_locale(char *a1p, int len1, char *a2p, int len2, SortSupport ssup);
129-
static int varstrcmp_abbrev(Datum x, Datum y, SortSupport ssup);
130129
static Datum varstr_abbrev_convert(Datum original, SortSupport ssup);
131130
static bool varstr_abbrev_abort(int memtupcount, SortSupport ssup);
132131
static int32 text_length(Datum str);
@@ -2159,7 +2158,7 @@ varstr_sortsupport(SortSupport ssup, Oid typid, Oid collid)
21592158
initHyperLogLog(&sss->abbr_card, 10);
21602159
initHyperLogLog(&sss->full_card, 10);
21612160
ssup->abbrev_full_comparator = ssup->comparator;
2162-
ssup->comparator = varstrcmp_abbrev;
2161+
ssup->comparator = ssup_datum_unsigned_cmp;
21632162
ssup->abbrev_converter = varstr_abbrev_convert;
21642163
ssup->abbrev_abort = varstr_abbrev_abort;
21652164
}
@@ -2445,27 +2444,6 @@ varstrfastcmp_locale(char *a1p, int len1, char *a2p, int len2, SortSupport ssup)
24452444
return result;
24462445
}
24472446

2448-
/*
2449-
* Abbreviated key comparison func
2450-
*/
2451-
static int
2452-
varstrcmp_abbrev(Datum x, Datum y, SortSupport ssup)
2453-
{
2454-
/*
2455-
* When 0 is returned, the core system will call varstrfastcmp_c()
2456-
* (bpcharfastcmp_c() in BpChar case) or varlenafastcmp_locale(). Even a
2457-
* strcmp() on two non-truncated strxfrm() blobs cannot indicate *equality*
2458-
* authoritatively, for the same reason that there is a strcoll()
2459-
* tie-breaker call to strcmp() in varstr_cmp().
2460-
*/
2461-
if (x > y)
2462-
return 1;
2463-
else if (x == y)
2464-
return 0;
2465-
else
2466-
return -1;
2467-
}
2468-
24692447
/*
24702448
* Conversion routine for sortsupport. Converts original to abbreviated key
24712449
* representation. Our encoding strategy is simple -- pack the first 8 bytes
@@ -2504,7 +2482,7 @@ varstr_abbrev_convert(Datum original, SortSupport ssup)
25042482
* strings may contain NUL bytes. Besides, this should be faster, too.
25052483
*
25062484
* More generally, it's okay that bytea callers can have NUL bytes in
2507-
* strings because varstrcmp_abbrev() need not make a distinction between
2485+
* strings because abbreviated cmp need not make a distinction between
25082486
* terminating NUL bytes, and NUL bytes representing actual NULs in the
25092487
* authoritative representation. Hopefully a comparison at or past one
25102488
* abbreviated key's terminating NUL byte will resolve the comparison
@@ -2694,10 +2672,10 @@ varstr_abbrev_convert(Datum original, SortSupport ssup)
26942672
/*
26952673
* Byteswap on little-endian machines.
26962674
*
2697-
* This is needed so that varstrcmp_abbrev() (an unsigned integer 3-way
2698-
* comparator) works correctly on all platforms. If we didn't do this,
2699-
* the comparator would have to call memcmp() with a pair of pointers to
2700-
* the first byte of each abbreviated key, which is slower.
2675+
* This is needed so that ssup_datum_unsigned_cmp() (an unsigned integer
2676+
* 3-way comparator) works correctly on all platforms. If we didn't do
2677+
* this, the comparator would have to call memcmp() with a pair of pointers
2678+
* to the first byte of each abbreviated key, which is slower.
27012679
*/
27022680
res = DatumBigEndianToNative(res);
27032681

0 commit comments

Comments
 (0)