Skip to content

Commit b648b70

Browse files
committed
Speed up CREATE INDEX CONCURRENTLY's TID sort.
Encode TIDs as 64-bit integers to speed up comparisons. This seems to speed things up on all platforms, but is even more beneficial when 8-byte integers are passed by value. Peter Geoghegan. Design suggestions and review by Tom Lane. Review also by Simon Riggs and by me.
1 parent f27a6b1 commit b648b70

File tree

1 file changed

+67
-4
lines changed

1 file changed

+67
-4
lines changed

src/backend/catalog/index.c

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ static void index_update_stats(Relation rel,
109109
static void IndexCheckExclusion(Relation heapRelation,
110110
Relation indexRelation,
111111
IndexInfo *indexInfo);
112+
static inline int64 itemptr_encode(ItemPointer itemptr);
113+
static inline void itemptr_decode(ItemPointer itemptr, int64 encoded);
112114
static bool validate_index_callback(ItemPointer itemptr, void *opaque);
113115
static void validate_index_heapscan(Relation heapRelation,
114116
Relation indexRelation,
@@ -2832,7 +2834,13 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
28322834
ivinfo.num_heap_tuples = heapRelation->rd_rel->reltuples;
28332835
ivinfo.strategy = NULL;
28342836

2835-
state.tuplesort = tuplesort_begin_datum(TIDOID, TIDLessOperator,
2837+
/*
2838+
* Encode TIDs as int8 values for the sort, rather than directly sorting
2839+
* item pointers. This can be significantly faster, primarily because TID
2840+
* is a pass-by-reference type on all platforms, whereas int8 is
2841+
* pass-by-value on most platforms.
2842+
*/
2843+
state.tuplesort = tuplesort_begin_datum(INT8OID, Int8LessOperator,
28362844
InvalidOid, false,
28372845
maintenance_work_mem,
28382846
false);
@@ -2871,15 +2879,56 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
28712879
heap_close(heapRelation, NoLock);
28722880
}
28732881

2882+
/*
2883+
* itemptr_encode - Encode ItemPointer as int64/int8
2884+
*
2885+
* This representation must produce values encoded as int64 that sort in the
2886+
* same order as their corresponding original TID values would (using the
2887+
* default int8 opclass to produce a result equivalent to the default TID
2888+
* opclass).
2889+
*
2890+
* As noted in validate_index(), this can be significantly faster.
2891+
*/
2892+
static inline int64
2893+
itemptr_encode(ItemPointer itemptr)
2894+
{
2895+
BlockNumber block = ItemPointerGetBlockNumber(itemptr);
2896+
OffsetNumber offset = ItemPointerGetOffsetNumber(itemptr);
2897+
int64 encoded;
2898+
2899+
/*
2900+
* Use the 16 least significant bits for the offset. 32 adjacent bits are
2901+
* used for the block number. Since remaining bits are unused, there
2902+
* cannot be negative encoded values (We assume a two's complement
2903+
* representation).
2904+
*/
2905+
encoded = ((uint64) block << 16) | (uint16) offset;
2906+
2907+
return encoded;
2908+
}
2909+
2910+
/*
2911+
* itemptr_decode - Decode int64/int8 representation back to ItemPointer
2912+
*/
2913+
static inline void
2914+
itemptr_decode(ItemPointer itemptr, int64 encoded)
2915+
{
2916+
BlockNumber block = (BlockNumber) (encoded >> 16);
2917+
OffsetNumber offset = (OffsetNumber) (encoded & 0xFFFF);
2918+
2919+
ItemPointerSet(itemptr, block, offset);
2920+
}
2921+
28742922
/*
28752923
* validate_index_callback - bulkdelete callback to collect the index TIDs
28762924
*/
28772925
static bool
28782926
validate_index_callback(ItemPointer itemptr, void *opaque)
28792927
{
28802928
v_i_state *state = (v_i_state *) opaque;
2929+
int64 encoded = itemptr_encode(itemptr);
28812930

2882-
tuplesort_putdatum(state->tuplesort, PointerGetDatum(itemptr), false);
2931+
tuplesort_putdatum(state->tuplesort, Int64GetDatum(encoded), false);
28832932
state->itups += 1;
28842933
return false; /* never actually delete anything */
28852934
}
@@ -2911,6 +2960,7 @@ validate_index_heapscan(Relation heapRelation,
29112960

29122961
/* state variables for the merge */
29132962
ItemPointer indexcursor = NULL;
2963+
ItemPointerData decoded;
29142964
bool tuplesort_empty = false;
29152965

29162966
/*
@@ -3020,13 +3070,26 @@ validate_index_heapscan(Relation heapRelation,
30203070
*/
30213071
if (ItemPointerGetBlockNumber(indexcursor) == root_blkno)
30223072
in_index[ItemPointerGetOffsetNumber(indexcursor) - 1] = true;
3023-
pfree(indexcursor);
30243073
}
30253074

30263075
tuplesort_empty = !tuplesort_getdatum(state->tuplesort, true,
30273076
&ts_val, &ts_isnull);
30283077
Assert(tuplesort_empty || !ts_isnull);
3029-
indexcursor = (ItemPointer) DatumGetPointer(ts_val);
3078+
if (!tuplesort_empty)
3079+
{
3080+
itemptr_decode(&decoded, DatumGetInt64(ts_val));
3081+
indexcursor = &decoded;
3082+
3083+
/* If int8 is pass-by-ref, free (encoded) TID Datum memory */
3084+
#ifndef USE_FLOAT8_BYVAL
3085+
pfree(DatumGetPointer(ts_val));
3086+
#endif
3087+
}
3088+
else
3089+
{
3090+
/* Be tidy */
3091+
indexcursor = NULL;
3092+
}
30303093
}
30313094

30323095
/*

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy