Commit e3931d01 authored by Michael Paquier's avatar Michael Paquier

Use multi-inserts for pg_attribute and pg_shdepend

For pg_attribute, this allows to insert at once a full set of attributes
for a relation (roughly 15% of WAL reduction in extreme cases).  For
pg_shdepend, this reduces the work done when creating new shared
dependencies from a database template.  The number of slots used for the
insertion is capped at 64kB of data inserted for both, depending on the
number of items to insert and the length of the rows involved.

More can be done for other catalogs, like pg_depend.  This part requires
a different approach as the number of slots to use depends also on the
number of entries discarded as pinned dependencies.  This is also
related to the rework or dependency handling for ALTER TABLE and CREATE
TABLE, mainly.

Author: Daniel Gustafsson
Reviewed-by: Andres Freund, Michael Paquier
Discussion: https://postgr.es/m/20190213182737.mxn6hkdxwrzgxk35@alap3.anarazel.de
parent cab2556f
......@@ -2164,8 +2164,8 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
RelationPutHeapTuple(relation, buffer, heaptuples[ndone], false);
/*
* Note that heap_multi_insert is not used for catalog tuples yet, but
* this will cover the gap once that is the case.
* For logical decoding we need combocids to properly decode the
* catalog.
*/
if (needwal && need_cids)
log_heap_new_cid(relation, heaptuples[ndone]);
......@@ -2180,8 +2180,8 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
RelationPutHeapTuple(relation, buffer, heaptup, false);
/*
* We don't use heap_multi_insert for catalog tuples yet, but
* better be prepared...
* For logical decoding we need combocids to properly decode the
* catalog.
*/
if (needwal && need_cids)
log_heap_new_cid(relation, heaptup);
......
This diff is collapsed.
......@@ -106,8 +106,7 @@ static TupleDesc ConstructTupleDescriptor(Relation heapRelation,
Oid *classObjectId);
static void InitializeAttributeOids(Relation indexRelation,
int numatts, Oid indexoid);
static void AppendAttributeTuples(Relation indexRelation, int numatts,
Datum *attopts);
static void AppendAttributeTuples(Relation indexRelation, Datum *attopts);
static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
Oid parentIndexId,
IndexInfo *indexInfo,
......@@ -485,12 +484,11 @@ InitializeAttributeOids(Relation indexRelation,
* ----------------------------------------------------------------
*/
static void
AppendAttributeTuples(Relation indexRelation, int numatts, Datum *attopts)
AppendAttributeTuples(Relation indexRelation, Datum *attopts)
{
Relation pg_attribute;
CatalogIndexState indstate;
TupleDesc indexTupDesc;
int i;
/*
* open the attribute relation and its indexes
......@@ -504,15 +502,7 @@ AppendAttributeTuples(Relation indexRelation, int numatts, Datum *attopts)
*/
indexTupDesc = RelationGetDescr(indexRelation);
for (i = 0; i < numatts; i++)
{
Form_pg_attribute attr = TupleDescAttr(indexTupDesc, i);
Datum attoptions = attopts ? attopts[i] : (Datum) 0;
Assert(attr->attnum == i + 1);
InsertPgAttributeTuple(pg_attribute, attr, attoptions, indstate);
}
InsertPgAttributeTuples(pg_attribute, indexTupDesc, InvalidOid, attopts, indstate);
CatalogCloseIndexes(indstate);
......@@ -979,8 +969,7 @@ index_create(Relation heapRelation,
/*
* append ATTRIBUTE tuples for the index
*/
AppendAttributeTuples(indexRelation, indexInfo->ii_NumIndexAttrs,
indexInfo->ii_OpclassOptions);
AppendAttributeTuples(indexRelation, indexInfo->ii_OpclassOptions);
/* ----------------
* update pg_index
......
......@@ -18,6 +18,7 @@
#include "access/genam.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/xact.h"
#include "catalog/index.h"
#include "catalog/indexing.h"
#include "executor/executor.h"
......@@ -250,6 +251,41 @@ CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup,
CatalogIndexInsert(indstate, tup);
}
/*
* CatalogTuplesMultiInsertWithInfo - as above, but for multiple tuples
*
* Insert multiple tuples into the given catalog relation at once, with an
* amortized cost of CatalogOpenIndexes.
*/
void
CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot,
int ntuples, CatalogIndexState indstate)
{
/* Nothing to do */
if (ntuples <= 0)
return;
heap_multi_insert(heapRel, slot, ntuples,
GetCurrentCommandId(true), 0, NULL);
/*
* There is no equivalent to heap_multi_insert for the catalog indexes, so
* we must loop over and insert individually.
*/
for (int i = 0; i < ntuples; i++)
{
bool should_free;
HeapTuple tuple;
tuple = ExecFetchSlotHeapTuple(slot[i], true, &should_free);
tuple->t_tableOid = slot[i]->tts_tableOid;
CatalogIndexInsert(indstate, tuple);
if (should_free)
heap_freetuple(tuple);
}
}
/*
* CatalogTupleUpdate - do heap and indexing work for updating a catalog tuple
*
......
......@@ -785,6 +785,13 @@ checkSharedDependencies(Oid classId, Oid objectId,
return true;
}
/*
* Cap the maximum amount of bytes allocated for copyTemplateDependencies()
* slots.
*/
#define MAX_PGSHDEPEND_INSERT_BYTES 65535
/*
* copyTemplateDependencies
*
......@@ -799,14 +806,19 @@ copyTemplateDependencies(Oid templateDbId, Oid newDbId)
ScanKeyData key[1];
SysScanDesc scan;
HeapTuple tup;
int slotCount;
CatalogIndexState indstate;
Datum values[Natts_pg_shdepend];
bool nulls[Natts_pg_shdepend];
bool replace[Natts_pg_shdepend];
TupleTableSlot **slot;
int nslots;
sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
sdepDesc = RelationGetDescr(sdepRel);
nslots = MAX_PGSHDEPEND_INSERT_BYTES / sizeof(FormData_pg_shdepend);
slot = palloc(sizeof(TupleTableSlot *) * nslots);
for (int i = 0; i < nslots; i++)
slot[i] = MakeSingleTupleTableSlot(sdepDesc, &TTSOpsHeapTuple);
indstate = CatalogOpenIndexes(sdepRel);
/* Scan all entries with dbid = templateDbId */
......@@ -818,14 +830,6 @@ copyTemplateDependencies(Oid templateDbId, Oid newDbId)
scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
NULL, 1, key);
/* Set up to copy the tuples except for inserting newDbId */
memset(values, 0, sizeof(values));
memset(nulls, false, sizeof(nulls));
memset(replace, false, sizeof(replace));
replace[Anum_pg_shdepend_dbid - 1] = true;
values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(newDbId);
/*
* Copy the entries of the original database, changing the database Id to
* that of the new database. Note that because we are not copying rows
......@@ -833,20 +837,46 @@ copyTemplateDependencies(Oid templateDbId, Oid newDbId)
* copy the ownership dependency of the template database itself; this is
* what we want.
*/
slotCount = 0;
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
HeapTuple newtup;
Form_pg_shdepend shdep;
ExecClearTuple(slot[slotCount]);
shdep = (Form_pg_shdepend) GETSTRUCT(tup);
slot[slotCount]->tts_values[Anum_pg_shdepend_dbid] = ObjectIdGetDatum(newDbId);
slot[slotCount]->tts_values[Anum_pg_shdepend_classid] = shdep->classid;
slot[slotCount]->tts_values[Anum_pg_shdepend_objid] = shdep->objid;
slot[slotCount]->tts_values[Anum_pg_shdepend_objsubid] = shdep->objsubid;
slot[slotCount]->tts_values[Anum_pg_shdepend_refclassid] = shdep->refclassid;
slot[slotCount]->tts_values[Anum_pg_shdepend_refobjid] = shdep->refobjid;
slot[slotCount]->tts_values[Anum_pg_shdepend_deptype] = shdep->deptype;
newtup = heap_modify_tuple(tup, sdepDesc, values, nulls, replace);
CatalogTupleInsertWithInfo(sdepRel, newtup, indstate);
ExecStoreVirtualTuple(slot[slotCount]);
slotCount++;
heap_freetuple(newtup);
/* If slots are full, insert a batch of tuples */
if (slotCount == nslots)
{
CatalogTuplesMultiInsertWithInfo(sdepRel, slot, slotCount, indstate);
slotCount = 0;
}
}
/* Insert any tuples left in the buffer */
if (slotCount > 0)
CatalogTuplesMultiInsertWithInfo(sdepRel, slot, slotCount, indstate);
systable_endscan(scan);
CatalogCloseIndexes(indstate);
table_close(sdepRel, RowExclusiveLock);
for (int i = 0; i < nslots; i++)
ExecDropSingleTupleTableSlot(slot[i]);
pfree(slot);
}
/*
......
......@@ -5975,6 +5975,8 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
AlterTableCmd *childcmd;
AclResult aclresult;
ObjectAddress address;
TupleDesc tupdesc;
FormData_pg_attribute *aattr[] = {&attribute};
/* At top level, permission check was done in ATPrepCmd, else do it */
if (recursing)
......@@ -6128,11 +6130,13 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
attribute.attislocal = colDef->is_local;
attribute.attinhcount = colDef->inhcount;
attribute.attcollation = collOid;
/* attribute.attacl is handled by InsertPgAttributeTuple */
/* attribute.attacl is handled by InsertPgAttributeTuples() */
ReleaseSysCache(typeTuple);
InsertPgAttributeTuple(attrdesc, &attribute, (Datum) 0, NULL);
tupdesc = CreateTupleDesc(lengthof(aattr), (FormData_pg_attribute **) &aattr);
InsertPgAttributeTuples(attrdesc, tupdesc, myrelid, NULL, NULL);
table_close(attrdesc, RowExclusiveLock);
......
......@@ -93,10 +93,11 @@ extern void heap_truncate_check_FKs(List *relations, bool tempTables);
extern List *heap_truncate_find_FKs(List *relationIds);
extern void InsertPgAttributeTuple(Relation pg_attribute_rel,
Form_pg_attribute new_attribute,
Datum attoptions,
CatalogIndexState indstate);
extern void InsertPgAttributeTuples(Relation pg_attribute_rel,
TupleDesc tupdesc,
Oid new_rel_oid,
Datum *attoptions,
CatalogIndexState indstate);
extern void InsertPgClassTuple(Relation pg_class_desc,
Relation new_rel_desc,
......
......@@ -19,6 +19,7 @@
#define INDEXING_H
#include "access/htup.h"
#include "nodes/execnodes.h"
#include "utils/relcache.h"
/*
......@@ -36,6 +37,10 @@ extern void CatalogCloseIndexes(CatalogIndexState indstate);
extern void CatalogTupleInsert(Relation heapRel, HeapTuple tup);
extern void CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup,
CatalogIndexState indstate);
extern void CatalogTuplesMultiInsertWithInfo(Relation heapRel,
TupleTableSlot **slot,
int ntuples,
CatalogIndexState indstate);
extern void CatalogTupleUpdate(Relation heapRel, ItemPointer otid,
HeapTuple tup);
extern void CatalogTupleUpdateWithInfo(Relation heapRel,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment