diff options
author | Tomas Vondra <tomas.vondra@postgresql.org> | 2023-03-20 10:34:07 +0100 |
---|---|---|
committer | Tomas Vondra <tomas.vondra@postgresql.org> | 2023-03-20 11:02:42 +0100 |
commit | 19d8e2308bc51ec4ab993ce90077342c915dd116 (patch) | |
tree | 80742287fd696662b892802b6ced26e93e7d68fb /src/backend/utils/cache/relcache.c | |
parent | e8583126833a53f4eebe28a8de45d128f01ff664 (diff) | |
download | postgresql-19d8e2308bc51ec4ab993ce90077342c915dd116.tar.gz postgresql-19d8e2308bc51ec4ab993ce90077342c915dd116.zip |
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 5753d4ee32, but then got reverted by
e3fcca0d0d 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/05ebcb44-f383-86e3-4f31-0a97a55634cf@enterprisedb.com
Discussion: https://postgr.es/m/CAFp7QwpMRGcDAQumN7onN9HjrJ3u4X3ZRXdGFT0K5G2JWvnbWg%40mail.gmail.com
Diffstat (limited to 'src/backend/utils/cache/relcache.c')
-rw-r--r-- | src/backend/utils/cache/relcache.c | 70 |
1 files changed, 50 insertions, 20 deletions
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 13f79873733..40140de9589 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -2440,10 +2440,11 @@ RelationDestroyRelation(Relation relation, bool remember_tupdesc) list_free_deep(relation->rd_fkeylist); list_free(relation->rd_indexlist); list_free(relation->rd_statlist); - bms_free(relation->rd_indexattr); bms_free(relation->rd_keyattr); bms_free(relation->rd_pkattr); bms_free(relation->rd_idattr); + bms_free(relation->rd_hotblockingattr); + bms_free(relation->rd_summarizedattr); if (relation->rd_pubdesc) pfree(relation->rd_pubdesc); if (relation->rd_options) @@ -5167,10 +5168,11 @@ RelationGetIndexPredicate(Relation relation) Bitmapset * RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind) { - Bitmapset *indexattrs; /* indexed columns */ Bitmapset *uindexattrs; /* columns in unique indexes */ Bitmapset *pkindexattrs; /* columns in the primary index */ Bitmapset *idindexattrs; /* columns in the replica identity */ + Bitmapset *hotblockingattrs; /* columns with HOT blocking indexes */ + Bitmapset *summarizedattrs; /* columns with summarizing indexes */ List *indexoidlist; List *newindexoidlist; Oid relpkindex; @@ -5179,18 +5181,20 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind) MemoryContext oldcxt; /* Quick exit if we already computed the result. */ - if (relation->rd_indexattr != NULL) + if (relation->rd_attrsvalid) { switch (attrKind) { - case INDEX_ATTR_BITMAP_ALL: - return bms_copy(relation->rd_indexattr); case INDEX_ATTR_BITMAP_KEY: return bms_copy(relation->rd_keyattr); case INDEX_ATTR_BITMAP_PRIMARY_KEY: return bms_copy(relation->rd_pkattr); case INDEX_ATTR_BITMAP_IDENTITY_KEY: return bms_copy(relation->rd_idattr); + case INDEX_ATTR_BITMAP_HOT_BLOCKING: + return bms_copy(relation->rd_hotblockingattr); + case INDEX_ATTR_BITMAP_SUMMARIZED: + return bms_copy(relation->rd_summarizedattr); default: elog(ERROR, "unknown attrKind %u", attrKind); } @@ -5230,10 +5234,11 @@ restart: * CONCURRENTLY is far enough along that we should ignore the index, it * won't be returned at all by RelationGetIndexList. */ - indexattrs = NULL; uindexattrs = NULL; pkindexattrs = NULL; idindexattrs = NULL; + hotblockingattrs = NULL; + summarizedattrs = NULL; foreach(l, indexoidlist) { Oid indexOid = lfirst_oid(l); @@ -5246,6 +5251,7 @@ restart: bool isKey; /* candidate key */ bool isPK; /* primary key */ bool isIDKey; /* replica identity index */ + Bitmapset **attrs; indexDesc = index_open(indexOid, AccessShareLock); @@ -5283,6 +5289,16 @@ restart: /* Is this index the configured (or default) replica identity? */ isIDKey = (indexOid == relreplindex); + /* + * If the index is summarizing, it doesn't block HOT updates, but we + * may still need to update it (if the attributes were modified). So + * decide which bitmap we'll update in the following loop. + */ + if (indexDesc->rd_indam->amsummarizing) + attrs = &summarizedattrs; + else + attrs = &hotblockingattrs; + /* Collect simple attribute references */ for (i = 0; i < indexDesc->rd_index->indnatts; i++) { @@ -5291,15 +5307,21 @@ restart: /* * Since we have covering indexes with non-key columns, we must * handle them accurately here. non-key columns must be added into - * indexattrs, since they are in index, and HOT-update shouldn't - * miss them. Obviously, non-key columns couldn't be referenced by + * hotblockingattrs or summarizedattrs, since they are in index, + * and update shouldn't miss them. + * + * Summarizing indexes do not block HOT, but do need to be updated + * when the column value changes, thus require a separate + * attribute bitmapset. + * + * Obviously, non-key columns couldn't be referenced by * foreign key or identity key. Hence we do not include them into * uindexattrs, pkindexattrs and idindexattrs bitmaps. */ if (attrnum != 0) { - indexattrs = bms_add_member(indexattrs, - attrnum - FirstLowInvalidHeapAttributeNumber); + *attrs = bms_add_member(*attrs, + attrnum - FirstLowInvalidHeapAttributeNumber); if (isKey && i < indexDesc->rd_index->indnkeyatts) uindexattrs = bms_add_member(uindexattrs, @@ -5316,10 +5338,10 @@ restart: } /* Collect all attributes used in expressions, too */ - pull_varattnos(indexExpressions, 1, &indexattrs); + pull_varattnos(indexExpressions, 1, attrs); /* Collect all attributes in the index predicate, too */ - pull_varattnos(indexPredicate, 1, &indexattrs); + pull_varattnos(indexPredicate, 1, attrs); index_close(indexDesc, AccessShareLock); } @@ -5347,24 +5369,28 @@ restart: bms_free(uindexattrs); bms_free(pkindexattrs); bms_free(idindexattrs); - bms_free(indexattrs); + bms_free(hotblockingattrs); + bms_free(summarizedattrs); goto restart; } /* Don't leak the old values of these bitmaps, if any */ - bms_free(relation->rd_indexattr); - relation->rd_indexattr = NULL; + relation->rd_attrsvalid = false; bms_free(relation->rd_keyattr); relation->rd_keyattr = NULL; bms_free(relation->rd_pkattr); relation->rd_pkattr = NULL; bms_free(relation->rd_idattr); relation->rd_idattr = NULL; + bms_free(relation->rd_hotblockingattr); + relation->rd_hotblockingattr = NULL; + bms_free(relation->rd_summarizedattr); + relation->rd_summarizedattr = NULL; /* * Now save copies of the bitmaps in the relcache entry. We intentionally - * set rd_indexattr last, because that's the one that signals validity of + * set rd_attrsvalid last, because that's the one that signals validity of * the values; if we run out of memory before making that copy, we won't * leave the relcache entry looking like the other ones are valid but * empty. @@ -5373,20 +5399,24 @@ restart: relation->rd_keyattr = bms_copy(uindexattrs); relation->rd_pkattr = bms_copy(pkindexattrs); relation->rd_idattr = bms_copy(idindexattrs); - relation->rd_indexattr = bms_copy(indexattrs); + relation->rd_hotblockingattr = bms_copy(hotblockingattrs); + relation->rd_summarizedattr = bms_copy(summarizedattrs); + relation->rd_attrsvalid = true; MemoryContextSwitchTo(oldcxt); /* We return our original working copy for caller to play with */ switch (attrKind) { - case INDEX_ATTR_BITMAP_ALL: - return indexattrs; case INDEX_ATTR_BITMAP_KEY: return uindexattrs; case INDEX_ATTR_BITMAP_PRIMARY_KEY: return pkindexattrs; case INDEX_ATTR_BITMAP_IDENTITY_KEY: return idindexattrs; + case INDEX_ATTR_BITMAP_HOT_BLOCKING: + return hotblockingattrs; + case INDEX_ATTR_BITMAP_SUMMARIZED: + return summarizedattrs; default: elog(ERROR, "unknown attrKind %u", attrKind); return NULL; @@ -6307,7 +6337,7 @@ load_relcache_init_file(bool shared) rel->rd_indexlist = NIL; rel->rd_pkindex = InvalidOid; rel->rd_replidindex = InvalidOid; - rel->rd_indexattr = NULL; + rel->rd_attrsvalid = false; rel->rd_keyattr = NULL; rel->rd_pkattr = NULL; rel->rd_idattr = NULL; |