aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2017-02-09 11:52:12 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2017-02-09 11:52:12 -0500
commit86d911ec0f9d4643e9a47db42510959dec0ed76b (patch)
treeef0605eb3b8357a406b51dc22d25206a39cbc561 /src/backend
parent7c5d8c16e12e56c1043ff4a28e07a306a15c2b85 (diff)
downloadpostgresql-86d911ec0f9d4643e9a47db42510959dec0ed76b.tar.gz
postgresql-86d911ec0f9d4643e9a47db42510959dec0ed76b.zip
Allow index AMs to cache data across aminsert calls within a SQL command.
It's always been possible for index AMs to cache data across successive amgettuple calls within a single SQL command: the IndexScanDesc.opaque field is meant for precisely that. However, no comparable facility exists for amortizing setup work across successive aminsert calls. This patch adds such a feature and teaches GIN, GIST, and BRIN to use it to amortize catalog lookups they'd previously been doing on every call. (The other standard index AMs keep everything they need in the relcache, so there's little to improve there.) For GIN, the overall improvement in a statement that inserts many rows can be as much as 10%, though it seems a bit less for the other two. In addition, this makes a really significant difference in runtime for CLOBBER_CACHE_ALWAYS tests, since in those builds the repeated catalog lookups are vastly more expensive. The reason this has been hard up to now is that the aminsert function is not passed any useful place to cache per-statement data. What I chose to do is to add suitable fields to struct IndexInfo and pass that to aminsert. That's not widening the index AM API very much because IndexInfo is already within the ken of ambuild; in fact, by passing the same info to aminsert as to ambuild, this is really removing an inconsistency in the AM API. Discussion: https://postgr.es/m/27568.1486508680@sss.pgh.pa.us
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/access/brin/brin.c25
-rw-r--r--src/backend/access/gin/gininsert.c27
-rw-r--r--src/backend/access/gist/gist.c25
-rw-r--r--src/backend/access/hash/hash.c3
-rw-r--r--src/backend/access/heap/tuptoaster.c7
-rw-r--r--src/backend/access/index/indexam.c5
-rw-r--r--src/backend/access/nbtree/nbtree.c3
-rw-r--r--src/backend/access/spgist/spginsert.c3
-rw-r--r--src/backend/catalog/index.c7
-rw-r--r--src/backend/catalog/indexing.c3
-rw-r--r--src/backend/catalog/toasting.c2
-rw-r--r--src/backend/commands/constraint.c3
-rw-r--r--src/backend/commands/indexcmds.c4
-rw-r--r--src/backend/executor/execIndexing.c3
14 files changed, 79 insertions, 41 deletions
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
index b2afdb7bedb..4ff046b4b01 100644
--- a/src/backend/access/brin/brin.c
+++ b/src/backend/access/brin/brin.c
@@ -131,14 +131,15 @@ brinhandler(PG_FUNCTION_ARGS)
bool
brininsert(Relation idxRel, Datum *values, bool *nulls,
ItemPointer heaptid, Relation heapRel,
- IndexUniqueCheck checkUnique)
+ IndexUniqueCheck checkUnique,
+ IndexInfo *indexInfo)
{
BlockNumber pagesPerRange;
- BrinDesc *bdesc = NULL;
+ BrinDesc *bdesc = (BrinDesc *) indexInfo->ii_AmCache;
BrinRevmap *revmap;
Buffer buf = InvalidBuffer;
MemoryContext tupcxt = NULL;
- MemoryContext oldcxt = NULL;
+ MemoryContext oldcxt = CurrentMemoryContext;
revmap = brinRevmapInitialize(idxRel, &pagesPerRange, NULL);
@@ -163,14 +164,21 @@ brininsert(Relation idxRel, Datum *values, bool *nulls,
if (!brtup)
break;
- /* First time through? */
+ /* First time through in this statement? */
if (bdesc == NULL)
{
+ MemoryContextSwitchTo(indexInfo->ii_Context);
bdesc = brin_build_desc(idxRel);
+ indexInfo->ii_AmCache = (void *) bdesc;
+ MemoryContextSwitchTo(oldcxt);
+ }
+ /* First time through in this brininsert call? */
+ if (tupcxt == NULL)
+ {
tupcxt = AllocSetContextCreate(CurrentMemoryContext,
"brininsert cxt",
ALLOCSET_DEFAULT_SIZES);
- oldcxt = MemoryContextSwitchTo(tupcxt);
+ MemoryContextSwitchTo(tupcxt);
}
dtup = brin_deform_tuple(bdesc, brtup);
@@ -261,12 +269,9 @@ brininsert(Relation idxRel, Datum *values, bool *nulls,
brinRevmapTerminate(revmap);
if (BufferIsValid(buf))
ReleaseBuffer(buf);
- if (bdesc != NULL)
- {
- brin_free_desc(bdesc);
- MemoryContextSwitchTo(oldcxt);
+ MemoryContextSwitchTo(oldcxt);
+ if (tupcxt != NULL)
MemoryContextDelete(tupcxt);
- }
return false;
}
diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c
index 03a7235a0a3..3d3b9e08400 100644
--- a/src/backend/access/gin/gininsert.c
+++ b/src/backend/access/gin/gininsert.c
@@ -482,39 +482,48 @@ ginHeapTupleInsert(GinState *ginstate, OffsetNumber attnum,
bool
gininsert(Relation index, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
- IndexUniqueCheck checkUnique)
+ IndexUniqueCheck checkUnique,
+ IndexInfo *indexInfo)
{
- GinState ginstate;
+ GinState *ginstate = (GinState *) indexInfo->ii_AmCache;
MemoryContext oldCtx;
MemoryContext insertCtx;
int i;
+ /* Initialize GinState cache if first call in this statement */
+ if (ginstate == NULL)
+ {
+ oldCtx = MemoryContextSwitchTo(indexInfo->ii_Context);
+ ginstate = (GinState *) palloc(sizeof(GinState));
+ initGinState(ginstate, index);
+ indexInfo->ii_AmCache = (void *) ginstate;
+ MemoryContextSwitchTo(oldCtx);
+ }
+
insertCtx = AllocSetContextCreate(CurrentMemoryContext,
"Gin insert temporary context",
ALLOCSET_DEFAULT_SIZES);
oldCtx = MemoryContextSwitchTo(insertCtx);
- initGinState(&ginstate, index);
-
if (GinGetUseFastUpdate(index))
{
GinTupleCollector collector;
memset(&collector, 0, sizeof(GinTupleCollector));
- for (i = 0; i < ginstate.origTupdesc->natts; i++)
- ginHeapTupleFastCollect(&ginstate, &collector,
+ for (i = 0; i < ginstate->origTupdesc->natts; i++)
+ ginHeapTupleFastCollect(ginstate, &collector,
(OffsetNumber) (i + 1),
values[i], isnull[i],
ht_ctid);
- ginHeapTupleFastInsert(&ginstate, &collector);
+ ginHeapTupleFastInsert(ginstate, &collector);
}
else
{
- for (i = 0; i < ginstate.origTupdesc->natts; i++)
- ginHeapTupleInsert(&ginstate, (OffsetNumber) (i + 1),
+ for (i = 0; i < ginstate->origTupdesc->natts; i++)
+ ginHeapTupleInsert(ginstate, (OffsetNumber) (i + 1),
values[i], isnull[i],
ht_ctid);
}
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index c2247ad2f78..96ead531ea3 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -18,6 +18,7 @@
#include "access/gistscan.h"
#include "catalog/pg_collation.h"
#include "miscadmin.h"
+#include "nodes/execnodes.h"
#include "utils/builtins.h"
#include "utils/index_selfuncs.h"
#include "utils/memutils.h"
@@ -144,21 +145,23 @@ gistbuildempty(Relation index)
bool
gistinsert(Relation r, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
- IndexUniqueCheck checkUnique)
+ IndexUniqueCheck checkUnique,
+ IndexInfo *indexInfo)
{
+ GISTSTATE *giststate = (GISTSTATE *) indexInfo->ii_AmCache;
IndexTuple itup;
- GISTSTATE *giststate;
MemoryContext oldCxt;
- giststate = initGISTstate(r);
+ /* Initialize GISTSTATE cache if first call in this statement */
+ if (giststate == NULL)
+ {
+ oldCxt = MemoryContextSwitchTo(indexInfo->ii_Context);
+ giststate = initGISTstate(r);
+ giststate->tempCxt = createTempGistContext();
+ indexInfo->ii_AmCache = (void *) giststate;
+ MemoryContextSwitchTo(oldCxt);
+ }
- /*
- * We use the giststate's scan context as temp context too. This means
- * that any memory leaked by the support functions is not reclaimed until
- * end of insert. In most cases, we aren't going to call the support
- * functions very many times before finishing the insert, so this seems
- * cheaper than resetting a temp context for each function call.
- */
oldCxt = MemoryContextSwitchTo(giststate->tempCxt);
itup = gistFormTuple(giststate, r,
@@ -169,7 +172,7 @@ gistinsert(Relation r, Datum *values, bool *isnull,
/* cleanup */
MemoryContextSwitchTo(oldCxt);
- freeGISTstate(giststate);
+ MemoryContextReset(giststate->tempCxt);
return false;
}
diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c
index 97ad22aa6f3..bca77a80c3b 100644
--- a/src/backend/access/hash/hash.c
+++ b/src/backend/access/hash/hash.c
@@ -232,7 +232,8 @@ hashbuildCallback(Relation index,
bool
hashinsert(Relation rel, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
- IndexUniqueCheck checkUnique)
+ IndexUniqueCheck checkUnique,
+ IndexInfo *indexInfo)
{
Datum index_values[1];
bool index_isnull[1];
diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c
index 496648c42f0..19e70480028 100644
--- a/src/backend/access/heap/tuptoaster.c
+++ b/src/backend/access/heap/tuptoaster.c
@@ -1604,7 +1604,9 @@ toast_save_datum(Relation rel, Datum value,
* Create the index entry. We cheat a little here by not using
* FormIndexDatum: this relies on the knowledge that the index columns
* are the same as the initial columns of the table for all the
- * indexes.
+ * indexes. We also cheat by not providing an IndexInfo: this is okay
+ * for now because btree doesn't need one, but we might have to be
+ * more honest someday.
*
* Note also that there had better not be any user-created index on
* the TOAST table, since we don't bother to update anything else.
@@ -1617,7 +1619,8 @@ toast_save_datum(Relation rel, Datum value,
&(toasttup->t_self),
toastrel,
toastidxs[i]->rd_index->indisunique ?
- UNIQUE_CHECK_YES : UNIQUE_CHECK_NO);
+ UNIQUE_CHECK_YES : UNIQUE_CHECK_NO,
+ NULL);
}
/*
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index ba27c1e86d9..4e7eca73cce 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -196,7 +196,8 @@ index_insert(Relation indexRelation,
bool *isnull,
ItemPointer heap_t_ctid,
Relation heapRelation,
- IndexUniqueCheck checkUnique)
+ IndexUniqueCheck checkUnique,
+ IndexInfo *indexInfo)
{
RELATION_CHECKS;
CHECK_REL_PROCEDURE(aminsert);
@@ -208,7 +209,7 @@ index_insert(Relation indexRelation,
return indexRelation->rd_amroutine->aminsert(indexRelation, values, isnull,
heap_t_ctid, heapRelation,
- checkUnique);
+ checkUnique, indexInfo);
}
/*
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index 469e7abe4df..945e563fcc5 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -276,7 +276,8 @@ btbuildempty(Relation index)
bool
btinsert(Relation rel, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
- IndexUniqueCheck checkUnique)
+ IndexUniqueCheck checkUnique,
+ IndexInfo *indexInfo)
{
bool result;
IndexTuple itup;
diff --git a/src/backend/access/spgist/spginsert.c b/src/backend/access/spgist/spginsert.c
index b42f4b71399..14f8a9ee8e0 100644
--- a/src/backend/access/spgist/spginsert.c
+++ b/src/backend/access/spgist/spginsert.c
@@ -206,7 +206,8 @@ spgbuildempty(Relation index)
bool
spginsert(Relation index, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
- IndexUniqueCheck checkUnique)
+ IndexUniqueCheck checkUnique,
+ IndexInfo *indexInfo)
{
SpGistState spgstate;
MemoryContext oldCtx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 815a694cfcd..f8d92145e86 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1687,6 +1687,10 @@ BuildIndexInfo(Relation index)
ii->ii_Concurrent = false;
ii->ii_BrokenHotChain = false;
+ /* set up for possible use by index AM */
+ ii->ii_AmCache = NULL;
+ ii->ii_Context = CurrentMemoryContext;
+
return ii;
}
@@ -3158,7 +3162,8 @@ validate_index_heapscan(Relation heapRelation,
&rootTuple,
heapRelation,
indexInfo->ii_Unique ?
- UNIQUE_CHECK_YES : UNIQUE_CHECK_NO);
+ UNIQUE_CHECK_YES : UNIQUE_CHECK_NO,
+ indexInfo);
state->tups_inserted += 1;
}
diff --git a/src/backend/catalog/indexing.c b/src/backend/catalog/indexing.c
index 76268e1d2a2..abc344ad699 100644
--- a/src/backend/catalog/indexing.c
+++ b/src/backend/catalog/indexing.c
@@ -139,7 +139,8 @@ CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple)
&(heapTuple->t_self), /* tid of heap tuple */
heapRelation,
relationDescs[i]->rd_index->indisunique ?
- UNIQUE_CHECK_YES : UNIQUE_CHECK_NO);
+ UNIQUE_CHECK_YES : UNIQUE_CHECK_NO,
+ indexInfo);
}
ExecDropSingleTupleTableSlot(slot);
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index e5f773d51d0..0e4231668d4 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -315,6 +315,8 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
indexInfo->ii_ReadyForInserts = true;
indexInfo->ii_Concurrent = false;
indexInfo->ii_BrokenHotChain = false;
+ indexInfo->ii_AmCache = NULL;
+ indexInfo->ii_Context = CurrentMemoryContext;
collationObjectId[0] = InvalidOid;
collationObjectId[1] = InvalidOid;
diff --git a/src/backend/commands/constraint.c b/src/backend/commands/constraint.c
index e9eeacd03a9..e2544e51ed5 100644
--- a/src/backend/commands/constraint.c
+++ b/src/backend/commands/constraint.c
@@ -165,7 +165,8 @@ unique_key_recheck(PG_FUNCTION_ARGS)
* index will know about.
*/
index_insert(indexRel, values, isnull, &(new_row->t_self),
- trigdata->tg_relation, UNIQUE_CHECK_EXISTING);
+ trigdata->tg_relation, UNIQUE_CHECK_EXISTING,
+ indexInfo);
}
else
{
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index f4814c095b5..265e9b33f78 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -183,6 +183,8 @@ CheckIndexCompatible(Oid oldId,
indexInfo->ii_ExclusionOps = NULL;
indexInfo->ii_ExclusionProcs = NULL;
indexInfo->ii_ExclusionStrats = NULL;
+ indexInfo->ii_AmCache = NULL;
+ indexInfo->ii_Context = CurrentMemoryContext;
typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
@@ -562,6 +564,8 @@ DefineIndex(Oid relationId,
indexInfo->ii_ReadyForInserts = !stmt->concurrent;
indexInfo->ii_Concurrent = stmt->concurrent;
indexInfo->ii_BrokenHotChain = false;
+ indexInfo->ii_AmCache = NULL;
+ indexInfo->ii_Context = CurrentMemoryContext;
typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
diff --git a/src/backend/executor/execIndexing.c b/src/backend/executor/execIndexing.c
index 8d119f6a19b..5242dee0064 100644
--- a/src/backend/executor/execIndexing.c
+++ b/src/backend/executor/execIndexing.c
@@ -391,7 +391,8 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
isnull, /* null flags */
tupleid, /* tid of heap tuple */
heapRelation, /* heap relation */
- checkUnique); /* type of uniqueness check to do */
+ checkUnique, /* type of uniqueness check to do */
+ indexInfo); /* index AM may need this */
/*
* If the index has an associated exclusion constraint, check that.