aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2015-12-16 15:23:45 -0500
committerRobert Haas <rhaas@postgresql.org>2015-12-16 15:23:45 -0500
commitb648b70342fbe712383e8cd76dc8f7feaba9aaa3 (patch)
tree80c2ccf9e1ebb91f93bec8105f6112aa1c1e268e /src
parentf27a6b15e6566fba7748d0d9a3fc5bcfd52c4a1b (diff)
downloadpostgresql-b648b70342fbe712383e8cd76dc8f7feaba9aaa3.tar.gz
postgresql-b648b70342fbe712383e8cd76dc8f7feaba9aaa3.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/backend/catalog/index.c71
1 files changed, 67 insertions, 4 deletions
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index e59b163173c..c10be3d6996 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -109,6 +109,8 @@ static void index_update_stats(Relation rel,
static void IndexCheckExclusion(Relation heapRelation,
Relation indexRelation,
IndexInfo *indexInfo);
+static inline int64 itemptr_encode(ItemPointer itemptr);
+static inline void itemptr_decode(ItemPointer itemptr, int64 encoded);
static bool validate_index_callback(ItemPointer itemptr, void *opaque);
static void validate_index_heapscan(Relation heapRelation,
Relation indexRelation,
@@ -2832,7 +2834,13 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
ivinfo.num_heap_tuples = heapRelation->rd_rel->reltuples;
ivinfo.strategy = NULL;
- state.tuplesort = tuplesort_begin_datum(TIDOID, TIDLessOperator,
+ /*
+ * Encode TIDs as int8 values for the sort, rather than directly sorting
+ * item pointers. This can be significantly faster, primarily because TID
+ * is a pass-by-reference type on all platforms, whereas int8 is
+ * pass-by-value on most platforms.
+ */
+ state.tuplesort = tuplesort_begin_datum(INT8OID, Int8LessOperator,
InvalidOid, false,
maintenance_work_mem,
false);
@@ -2872,14 +2880,55 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
}
/*
+ * itemptr_encode - Encode ItemPointer as int64/int8
+ *
+ * This representation must produce values encoded as int64 that sort in the
+ * same order as their corresponding original TID values would (using the
+ * default int8 opclass to produce a result equivalent to the default TID
+ * opclass).
+ *
+ * As noted in validate_index(), this can be significantly faster.
+ */
+static inline int64
+itemptr_encode(ItemPointer itemptr)
+{
+ BlockNumber block = ItemPointerGetBlockNumber(itemptr);
+ OffsetNumber offset = ItemPointerGetOffsetNumber(itemptr);
+ int64 encoded;
+
+ /*
+ * Use the 16 least significant bits for the offset. 32 adjacent bits are
+ * used for the block number. Since remaining bits are unused, there
+ * cannot be negative encoded values (We assume a two's complement
+ * representation).
+ */
+ encoded = ((uint64) block << 16) | (uint16) offset;
+
+ return encoded;
+}
+
+/*
+ * itemptr_decode - Decode int64/int8 representation back to ItemPointer
+ */
+static inline void
+itemptr_decode(ItemPointer itemptr, int64 encoded)
+{
+ BlockNumber block = (BlockNumber) (encoded >> 16);
+ OffsetNumber offset = (OffsetNumber) (encoded & 0xFFFF);
+
+ ItemPointerSet(itemptr, block, offset);
+}
+
+/*
* validate_index_callback - bulkdelete callback to collect the index TIDs
*/
static bool
validate_index_callback(ItemPointer itemptr, void *opaque)
{
v_i_state *state = (v_i_state *) opaque;
+ int64 encoded = itemptr_encode(itemptr);
- tuplesort_putdatum(state->tuplesort, PointerGetDatum(itemptr), false);
+ tuplesort_putdatum(state->tuplesort, Int64GetDatum(encoded), false);
state->itups += 1;
return false; /* never actually delete anything */
}
@@ -2911,6 +2960,7 @@ validate_index_heapscan(Relation heapRelation,
/* state variables for the merge */
ItemPointer indexcursor = NULL;
+ ItemPointerData decoded;
bool tuplesort_empty = false;
/*
@@ -3020,13 +3070,26 @@ validate_index_heapscan(Relation heapRelation,
*/
if (ItemPointerGetBlockNumber(indexcursor) == root_blkno)
in_index[ItemPointerGetOffsetNumber(indexcursor) - 1] = true;
- pfree(indexcursor);
}
tuplesort_empty = !tuplesort_getdatum(state->tuplesort, true,
&ts_val, &ts_isnull);
Assert(tuplesort_empty || !ts_isnull);
- indexcursor = (ItemPointer) DatumGetPointer(ts_val);
+ if (!tuplesort_empty)
+ {
+ itemptr_decode(&decoded, DatumGetInt64(ts_val));
+ indexcursor = &decoded;
+
+ /* If int8 is pass-by-ref, free (encoded) TID Datum memory */
+#ifndef USE_FLOAT8_BYVAL
+ pfree(DatumGetPointer(ts_val));
+#endif
+ }
+ else
+ {
+ /* Be tidy */
+ indexcursor = NULL;
+ }
}
/*