Skip to content

Commit 19d8e23

Browse files
committed
Ignore BRIN indexes when checking for HOT updates
When determining whether an index update may be skipped by using HOT, we can ignore attributes indexed by block summarizing indexes without references to individual tuples that need to be cleaned up. A new type TU_UpdateIndexes provides a signal to the executor to determine which indexes to update - no indexes, all indexes, or only the summarizing indexes. This also removes rd_indexattr list, and replaces it with rd_attrsvalid flag. The list was not used anywhere, and a simple flag is sufficient. This was originally committed as 5753d4e, but then got reverted by e3fcca0 because of correctness issues. Original patch by Josef Simanek, various fixes and improvements by Tomas Vondra and me. Authors: Matthias van de Meent, Josef Simanek, Tomas Vondra Reviewed-by: Tomas Vondra, Alvaro Herrera Discussion: https://postgr.es/m/[email protected] Discussion: https://postgr.es/m/CAFp7QwpMRGcDAQumN7onN9HjrJ3u4X3ZRXdGFT0K5G2JWvnbWg%40mail.gmail.com
1 parent e858312 commit 19d8e23

File tree

30 files changed

+448
-76
lines changed

30 files changed

+448
-76
lines changed

doc/src/sgml/indexam.sgml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@ typedef struct IndexAmRoutine
127127
bool amcaninclude;
128128
/* does AM use maintenance_work_mem? */
129129
bool amusemaintenanceworkmem;
130+
/* does AM summarize tuples, with at least all tuples in the block
131+
* summarized in one summary */
132+
bool amsummarizing;
130133
/* OR of parallel vacuum flags */
131134
uint8 amparallelvacuumoptions;
132135
/* type of data stored in index, or InvalidOid if variable */
@@ -247,6 +250,16 @@ typedef struct IndexAmRoutine
247250
null, independently of <structfield>amoptionalkey</structfield>.
248251
</para>
249252

253+
<para>
254+
The <structfield>amsummarizing</structfield> flag indicates whether the
255+
access method summarizes the indexed tuples, with summarizing granularity
256+
of at least per block.
257+
Access methods that do not point to individual tuples, but to block ranges
258+
(like <acronym>BRIN</acronym>), may allow the <acronym>HOT</acronym> optimization
259+
to continue. This does not apply to attributes referenced in index
260+
predicates, an update of such attribute always disables <acronym>HOT</acronym>.
261+
</para>
262+
250263
</sect1>
251264

252265
<sect1 id="index-functions">

src/backend/access/brin/brin.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ brinhandler(PG_FUNCTION_ARGS)
109109
amroutine->amcanparallel = false;
110110
amroutine->amcaninclude = false;
111111
amroutine->amusemaintenanceworkmem = false;
112+
amroutine->amsummarizing = true;
112113
amroutine->amparallelvacuumoptions =
113114
VACUUM_OPTION_PARALLEL_CLEANUP;
114115
amroutine->amkeytype = InvalidOid;

src/backend/access/gin/ginutil.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ ginhandler(PG_FUNCTION_ARGS)
5656
amroutine->amcanparallel = false;
5757
amroutine->amcaninclude = false;
5858
amroutine->amusemaintenanceworkmem = true;
59+
amroutine->amsummarizing = false;
5960
amroutine->amparallelvacuumoptions =
6061
VACUUM_OPTION_PARALLEL_BULKDEL | VACUUM_OPTION_PARALLEL_CLEANUP;
6162
amroutine->amkeytype = InvalidOid;

src/backend/access/gist/gist.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ gisthandler(PG_FUNCTION_ARGS)
7878
amroutine->amcanparallel = false;
7979
amroutine->amcaninclude = true;
8080
amroutine->amusemaintenanceworkmem = false;
81+
amroutine->amsummarizing = false;
8182
amroutine->amparallelvacuumoptions =
8283
VACUUM_OPTION_PARALLEL_BULKDEL | VACUUM_OPTION_PARALLEL_COND_CLEANUP;
8384
amroutine->amkeytype = InvalidOid;

src/backend/access/hash/hash.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ hashhandler(PG_FUNCTION_ARGS)
7575
amroutine->amcanparallel = false;
7676
amroutine->amcaninclude = false;
7777
amroutine->amusemaintenanceworkmem = false;
78+
amroutine->amsummarizing = false;
7879
amroutine->amparallelvacuumoptions =
7980
VACUUM_OPTION_PARALLEL_BULKDEL;
8081
amroutine->amkeytype = INT4OID;

src/backend/access/heap/heapam.c

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2924,11 +2924,13 @@ simple_heap_delete(Relation relation, ItemPointer tid)
29242924
TM_Result
29252925
heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
29262926
CommandId cid, Snapshot crosscheck, bool wait,
2927-
TM_FailureData *tmfd, LockTupleMode *lockmode)
2927+
TM_FailureData *tmfd, LockTupleMode *lockmode,
2928+
TU_UpdateIndexes *update_indexes)
29282929
{
29292930
TM_Result result;
29302931
TransactionId xid = GetCurrentTransactionId();
29312932
Bitmapset *hot_attrs;
2933+
Bitmapset *sum_attrs;
29322934
Bitmapset *key_attrs;
29332935
Bitmapset *id_attrs;
29342936
Bitmapset *interesting_attrs;
@@ -2951,6 +2953,7 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
29512953
bool have_tuple_lock = false;
29522954
bool iscombo;
29532955
bool use_hot_update = false;
2956+
bool summarized_update = false;
29542957
bool key_intact;
29552958
bool all_visible_cleared = false;
29562959
bool all_visible_cleared_new = false;
@@ -2996,12 +2999,16 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
29962999
* Note that we get copies of each bitmap, so we need not worry about
29973000
* relcache flush happening midway through.
29983001
*/
2999-
hot_attrs = RelationGetIndexAttrBitmap(relation, INDEX_ATTR_BITMAP_ALL);
3002+
hot_attrs = RelationGetIndexAttrBitmap(relation,
3003+
INDEX_ATTR_BITMAP_HOT_BLOCKING);
3004+
sum_attrs = RelationGetIndexAttrBitmap(relation,
3005+
INDEX_ATTR_BITMAP_SUMMARIZED);
30003006
key_attrs = RelationGetIndexAttrBitmap(relation, INDEX_ATTR_BITMAP_KEY);
30013007
id_attrs = RelationGetIndexAttrBitmap(relation,
30023008
INDEX_ATTR_BITMAP_IDENTITY_KEY);
30033009
interesting_attrs = NULL;
30043010
interesting_attrs = bms_add_members(interesting_attrs, hot_attrs);
3011+
interesting_attrs = bms_add_members(interesting_attrs, sum_attrs);
30053012
interesting_attrs = bms_add_members(interesting_attrs, key_attrs);
30063013
interesting_attrs = bms_add_members(interesting_attrs, id_attrs);
30073014

@@ -3311,7 +3318,10 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
33113318
UnlockTupleTuplock(relation, &(oldtup.t_self), *lockmode);
33123319
if (vmbuffer != InvalidBuffer)
33133320
ReleaseBuffer(vmbuffer);
3321+
*update_indexes = TU_None;
3322+
33143323
bms_free(hot_attrs);
3324+
bms_free(sum_attrs);
33153325
bms_free(key_attrs);
33163326
bms_free(id_attrs);
33173327
bms_free(modified_attrs);
@@ -3633,7 +3643,19 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
36333643
* changed.
36343644
*/
36353645
if (!bms_overlap(modified_attrs, hot_attrs))
3646+
{
36363647
use_hot_update = true;
3648+
3649+
/*
3650+
* If none of the columns that are used in hot-blocking indexes
3651+
* were updated, we can apply HOT, but we do still need to check
3652+
* if we need to update the summarizing indexes, and update those
3653+
* indexes if the columns were updated, or we may fail to detect
3654+
* e.g. value bound changes in BRIN minmax indexes.
3655+
*/
3656+
if (bms_overlap(modified_attrs, sum_attrs))
3657+
summarized_update = true;
3658+
}
36373659
}
36383660
else
36393661
{
@@ -3793,10 +3815,27 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
37933815
heap_freetuple(heaptup);
37943816
}
37953817

3818+
/*
3819+
* If it is a HOT update, the update may still need to update summarized
3820+
* indexes, lest we fail to update those summaries and get incorrect
3821+
* results (for example, minmax bounds of the block may change with this
3822+
* update).
3823+
*/
3824+
if (use_hot_update)
3825+
{
3826+
if (summarized_update)
3827+
*update_indexes = TU_Summarizing;
3828+
else
3829+
*update_indexes = TU_None;
3830+
}
3831+
else
3832+
*update_indexes = TU_All;
3833+
37963834
if (old_key_tuple != NULL && old_key_copied)
37973835
heap_freetuple(old_key_tuple);
37983836

37993837
bms_free(hot_attrs);
3838+
bms_free(sum_attrs);
38003839
bms_free(key_attrs);
38013840
bms_free(id_attrs);
38023841
bms_free(modified_attrs);
@@ -3951,7 +3990,8 @@ HeapDetermineColumnsInfo(Relation relation,
39513990
* via ereport().
39523991
*/
39533992
void
3954-
simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup)
3993+
simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup,
3994+
TU_UpdateIndexes *update_indexes)
39553995
{
39563996
TM_Result result;
39573997
TM_FailureData tmfd;
@@ -3960,7 +4000,7 @@ simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup)
39604000
result = heap_update(relation, otid, tup,
39614001
GetCurrentCommandId(true), InvalidSnapshot,
39624002
true /* wait for commit */ ,
3963-
&tmfd, &lockmode);
4003+
&tmfd, &lockmode, update_indexes);
39644004
switch (result)
39654005
{
39664006
case TM_SelfModified:

src/backend/access/heap/heapam_handler.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ static TM_Result
314314
heapam_tuple_update(Relation relation, ItemPointer otid, TupleTableSlot *slot,
315315
CommandId cid, Snapshot snapshot, Snapshot crosscheck,
316316
bool wait, TM_FailureData *tmfd,
317-
LockTupleMode *lockmode, bool *update_indexes)
317+
LockTupleMode *lockmode, TU_UpdateIndexes *update_indexes)
318318
{
319319
bool shouldFree = true;
320320
HeapTuple tuple = ExecFetchSlotHeapTuple(slot, true, &shouldFree);
@@ -325,7 +325,7 @@ heapam_tuple_update(Relation relation, ItemPointer otid, TupleTableSlot *slot,
325325
tuple->t_tableOid = slot->tts_tableOid;
326326

327327
result = heap_update(relation, otid, tuple, cid, crosscheck, wait,
328-
tmfd, lockmode);
328+
tmfd, lockmode, update_indexes);
329329
ItemPointerCopy(&tuple->t_self, &slot->tts_tid);
330330

331331
/*
@@ -334,9 +334,20 @@ heapam_tuple_update(Relation relation, ItemPointer otid, TupleTableSlot *slot,
334334
* Note: heap_update returns the tid (location) of the new tuple in the
335335
* t_self field.
336336
*
337-
* If it's a HOT update, we mustn't insert new index entries.
337+
* If the update is not HOT, we must update all indexes. If the update
338+
* is HOT, it could be that we updated summarized columns, so we either
339+
* update only summarized indexes, or none at all.
338340
*/
339-
*update_indexes = result == TM_Ok && !HeapTupleIsHeapOnly(tuple);
341+
if (result != TM_Ok)
342+
{
343+
Assert(*update_indexes == TU_None);
344+
*update_indexes = TU_None;
345+
}
346+
else if (!HeapTupleIsHeapOnly(tuple))
347+
Assert(*update_indexes == TU_All);
348+
else
349+
Assert((*update_indexes == TU_Summarizing) ||
350+
(*update_indexes == TU_None));
340351

341352
if (shouldFree)
342353
pfree(tuple);

src/backend/access/nbtree/nbtree.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ bthandler(PG_FUNCTION_ARGS)
114114
amroutine->amcanparallel = true;
115115
amroutine->amcaninclude = true;
116116
amroutine->amusemaintenanceworkmem = false;
117+
amroutine->amsummarizing = false;
117118
amroutine->amparallelvacuumoptions =
118119
VACUUM_OPTION_PARALLEL_BULKDEL | VACUUM_OPTION_PARALLEL_COND_CLEANUP;
119120
amroutine->amkeytype = InvalidOid;

src/backend/access/spgist/spgutils.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ spghandler(PG_FUNCTION_ARGS)
6262
amroutine->amcanparallel = false;
6363
amroutine->amcaninclude = true;
6464
amroutine->amusemaintenanceworkmem = false;
65+
amroutine->amsummarizing = false;
6566
amroutine->amparallelvacuumoptions =
6667
VACUUM_OPTION_PARALLEL_BULKDEL | VACUUM_OPTION_PARALLEL_COND_CLEANUP;
6768
amroutine->amkeytype = InvalidOid;

src/backend/access/table/tableam.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ void
345345
simple_table_tuple_update(Relation rel, ItemPointer otid,
346346
TupleTableSlot *slot,
347347
Snapshot snapshot,
348-
bool *update_indexes)
348+
TU_UpdateIndexes *update_indexes)
349349
{
350350
TM_Result result;
351351
TM_FailureData tmfd;

0 commit comments

Comments
 (0)