Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite3931d0

Browse files
committed
Use multi-inserts for pg_attribute and pg_shdepend
For pg_attribute, this allows to insert at once a full set of attributesfor a relation (roughly 15% of WAL reduction in extreme cases). Forpg_shdepend, this reduces the work done when creating new shareddependencies from a database template. The number of slots used for theinsertion is capped at 64kB of data inserted for both, depending on thenumber of items to insert and the length of the rows involved.More can be done for other catalogs, like pg_depend. This part requiresa different approach as the number of slots to use depends also on thenumber of entries discarded as pinned dependencies. This is alsorelated to the rework or dependency handling for ALTER TABLE and CREATETABLE, mainly.Author: Daniel GustafssonReviewed-by: Andres Freund, Michael PaquierDiscussion:https://postgr.es/m/20190213182737.mxn6hkdxwrzgxk35@alap3.anarazel.de
1 parentcab2556 commite3931d0

File tree

8 files changed

+225
-119
lines changed

8 files changed

+225
-119
lines changed

‎src/backend/access/heap/heapam.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2164,8 +2164,8 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
21642164
RelationPutHeapTuple(relation,buffer,heaptuples[ndone], false);
21652165

21662166
/*
2167-
*Note that heap_multi_insert is not used for catalog tuples yet, but
2168-
*this will cover the gap once that is the case.
2167+
*For logical decoding we need combocids to properly decode the
2168+
*catalog.
21692169
*/
21702170
if (needwal&&need_cids)
21712171
log_heap_new_cid(relation,heaptuples[ndone]);
@@ -2180,8 +2180,8 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
21802180
RelationPutHeapTuple(relation,buffer,heaptup, false);
21812181

21822182
/*
2183-
*We don't use heap_multi_insert for catalog tuples yet, but
2184-
*better be prepared...
2183+
*For logical decoding we need combocids to properly decode the
2184+
*catalog.
21852185
*/
21862186
if (needwal&&need_cids)
21872187
log_heap_new_cid(relation,heaptup);

‎src/backend/catalog/heap.c

Lines changed: 120 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -710,70 +710,122 @@ CheckAttributeType(const char *attname,
710710
}
711711

712712
/*
713-
* InsertPgAttributeTuple
714-
*Construct and insert a new tuple in pg_attribute.
713+
* Cap the maximum amount of bytes allocated for InsertPgAttributeTuples()
714+
* slots.
715+
*/
716+
#defineMAX_PGATTRIBUTE_INSERT_BYTES 65535
717+
718+
/*
719+
* InsertPgAttributeTuples
720+
*Construct and insert a set of tuples in pg_attribute.
715721
*
716-
* Caller has already opened and locked pg_attribute. new_attribute is the
717-
* attribute to insert. attcacheoff is always initialized to -1, attacl,
718-
* attfdwoptions and attmissingval are always initialized to NULL.
722+
* Caller has already opened and locked pg_attribute. tupdesc contains the
723+
* attributes to insert. attcacheoff is always initialized to -1, attacl,
724+
* attfdwoptions and attmissingval are always initialized to NULL. attoptions
725+
* must contain the same number of elements as tupdesc, or be NULL.
719726
*
720727
* indstate is the index state for CatalogTupleInsertWithInfo. It can be
721728
* passed as NULL, in which case we'll fetch the necessary info. (Don't do
722729
* this when inserting multiple attributes, because it's a tad more
723730
* expensive.)
731+
*
732+
* new_rel_oid is the relation OID assigned to the attributes inserted.
733+
* If set to InvalidOid, the relation OID from tupdesc is used instead.
724734
*/
725735
void
726-
InsertPgAttributeTuple(Relationpg_attribute_rel,
727-
Form_pg_attributenew_attribute,
728-
Datumattoptions,
729-
CatalogIndexStateindstate)
736+
InsertPgAttributeTuples(Relationpg_attribute_rel,
737+
TupleDesctupdesc,
738+
Oidnew_rel_oid,
739+
Datum*attoptions,
740+
CatalogIndexStateindstate)
730741
{
731-
Datumvalues[Natts_pg_attribute];
732-
boolnulls[Natts_pg_attribute];
733-
HeapTupletup;
742+
TupleTableSlot**slot;
743+
TupleDesctd;
744+
intnslots;
745+
intnatts=0;
746+
intslotCount=0;
747+
boolclose_index= false;
748+
749+
td=RelationGetDescr(pg_attribute_rel);
750+
751+
/* Initialize the number of slots to use */
752+
nslots=Min(tupdesc->natts,
753+
(MAX_PGATTRIBUTE_INSERT_BYTES /sizeof(FormData_pg_attribute)));
754+
slot=palloc(sizeof(TupleTableSlot*)*nslots);
755+
for (inti=0;i<nslots;i++)
756+
slot[i]=MakeSingleTupleTableSlot(td,&TTSOpsHeapTuple);
757+
758+
while (natts<tupdesc->natts)
759+
{
760+
Form_pg_attributeattrs=TupleDescAttr(tupdesc,natts);
734761

735-
/* This is a tad tedious, but way cleaner than what we used to do... */
736-
memset(values,0,sizeof(values));
737-
memset(nulls, false,sizeof(nulls));
762+
ExecClearTuple(slot[slotCount]);
738763

739-
values[Anum_pg_attribute_attrelid-1]=ObjectIdGetDatum(new_attribute->attrelid);
740-
values[Anum_pg_attribute_attname-1]=NameGetDatum(&new_attribute->attname);
741-
values[Anum_pg_attribute_atttypid-1]=ObjectIdGetDatum(new_attribute->atttypid);
742-
values[Anum_pg_attribute_attstattarget-1]=Int32GetDatum(new_attribute->attstattarget);
743-
values[Anum_pg_attribute_attlen-1]=Int16GetDatum(new_attribute->attlen);
744-
values[Anum_pg_attribute_attnum-1]=Int16GetDatum(new_attribute->attnum);
745-
values[Anum_pg_attribute_attndims-1]=Int32GetDatum(new_attribute->attndims);
746-
values[Anum_pg_attribute_attcacheoff-1]=Int32GetDatum(-1);
747-
values[Anum_pg_attribute_atttypmod-1]=Int32GetDatum(new_attribute->atttypmod);
748-
values[Anum_pg_attribute_attbyval-1]=BoolGetDatum(new_attribute->attbyval);
749-
values[Anum_pg_attribute_attstorage-1]=CharGetDatum(new_attribute->attstorage);
750-
values[Anum_pg_attribute_attalign-1]=CharGetDatum(new_attribute->attalign);
751-
values[Anum_pg_attribute_attnotnull-1]=BoolGetDatum(new_attribute->attnotnull);
752-
values[Anum_pg_attribute_atthasdef-1]=BoolGetDatum(new_attribute->atthasdef);
753-
values[Anum_pg_attribute_atthasmissing-1]=BoolGetDatum(new_attribute->atthasmissing);
754-
values[Anum_pg_attribute_attidentity-1]=CharGetDatum(new_attribute->attidentity);
755-
values[Anum_pg_attribute_attgenerated-1]=CharGetDatum(new_attribute->attgenerated);
756-
values[Anum_pg_attribute_attisdropped-1]=BoolGetDatum(new_attribute->attisdropped);
757-
values[Anum_pg_attribute_attislocal-1]=BoolGetDatum(new_attribute->attislocal);
758-
values[Anum_pg_attribute_attinhcount-1]=Int32GetDatum(new_attribute->attinhcount);
759-
values[Anum_pg_attribute_attcollation-1]=ObjectIdGetDatum(new_attribute->attcollation);
760-
values[Anum_pg_attribute_attoptions-1]=attoptions;
761-
762-
/* start out with empty permissions and empty options */
763-
nulls[Anum_pg_attribute_attacl-1]= true;
764-
nulls[Anum_pg_attribute_attoptions-1]=attoptions== (Datum)0;
765-
nulls[Anum_pg_attribute_attfdwoptions-1]= true;
766-
nulls[Anum_pg_attribute_attmissingval-1]= true;
767-
768-
tup=heap_form_tuple(RelationGetDescr(pg_attribute_rel),values,nulls);
764+
if (new_rel_oid!=InvalidOid)
765+
slot[slotCount]->tts_values[Anum_pg_attribute_attrelid-1]=ObjectIdGetDatum(new_rel_oid);
766+
else
767+
slot[slotCount]->tts_values[Anum_pg_attribute_attrelid-1]=ObjectIdGetDatum(attrs->attrelid);
768+
769+
slot[slotCount]->tts_values[Anum_pg_attribute_attname-1]=NameGetDatum(&attrs->attname);
770+
slot[slotCount]->tts_values[Anum_pg_attribute_atttypid-1]=ObjectIdGetDatum(attrs->atttypid);
771+
slot[slotCount]->tts_values[Anum_pg_attribute_attstattarget-1]=Int32GetDatum(attrs->attstattarget);
772+
slot[slotCount]->tts_values[Anum_pg_attribute_attlen-1]=Int16GetDatum(attrs->attlen);
773+
slot[slotCount]->tts_values[Anum_pg_attribute_attnum-1]=Int16GetDatum(attrs->attnum);
774+
slot[slotCount]->tts_values[Anum_pg_attribute_attndims-1]=Int32GetDatum(attrs->attndims);
775+
slot[slotCount]->tts_values[Anum_pg_attribute_attcacheoff-1]=Int32GetDatum(-1);
776+
slot[slotCount]->tts_values[Anum_pg_attribute_atttypmod-1]=Int32GetDatum(attrs->atttypmod);
777+
slot[slotCount]->tts_values[Anum_pg_attribute_attbyval-1]=BoolGetDatum(attrs->attbyval);
778+
slot[slotCount]->tts_values[Anum_pg_attribute_attstorage-1]=CharGetDatum(attrs->attstorage);
779+
slot[slotCount]->tts_values[Anum_pg_attribute_attalign-1]=CharGetDatum(attrs->attalign);
780+
slot[slotCount]->tts_values[Anum_pg_attribute_attnotnull-1]=BoolGetDatum(attrs->attnotnull);
781+
slot[slotCount]->tts_values[Anum_pg_attribute_atthasdef-1]=BoolGetDatum(attrs->atthasdef);
782+
slot[slotCount]->tts_values[Anum_pg_attribute_atthasmissing-1]=BoolGetDatum(attrs->atthasmissing);
783+
slot[slotCount]->tts_values[Anum_pg_attribute_attidentity-1]=CharGetDatum(attrs->attidentity);
784+
slot[slotCount]->tts_values[Anum_pg_attribute_attgenerated-1]=CharGetDatum(attrs->attgenerated);
785+
slot[slotCount]->tts_values[Anum_pg_attribute_attisdropped-1]=BoolGetDatum(attrs->attisdropped);
786+
slot[slotCount]->tts_values[Anum_pg_attribute_attislocal-1]=BoolGetDatum(attrs->attislocal);
787+
slot[slotCount]->tts_values[Anum_pg_attribute_attinhcount-1]=Int32GetDatum(attrs->attinhcount);
788+
slot[slotCount]->tts_values[Anum_pg_attribute_attcollation-1]=ObjectIdGetDatum(attrs->attcollation);
789+
if (attoptions&&attoptions[natts]!= (Datum)0)
790+
slot[slotCount]->tts_values[Anum_pg_attribute_attoptions-1]=attoptions[natts];
791+
else
792+
slot[slotCount]->tts_isnull[Anum_pg_attribute_attoptions-1]= true;
769793

770-
/* finally insert the new tuple, update the indexes, and clean up */
771-
if (indstate!=NULL)
772-
CatalogTupleInsertWithInfo(pg_attribute_rel,tup,indstate);
773-
else
774-
CatalogTupleInsert(pg_attribute_rel,tup);
794+
/* start out with empty permissions and empty options */
795+
slot[slotCount]->tts_isnull[Anum_pg_attribute_attacl-1]= true;
796+
slot[slotCount]->tts_isnull[Anum_pg_attribute_attfdwoptions-1]= true;
797+
slot[slotCount]->tts_isnull[Anum_pg_attribute_attmissingval-1]= true;
775798

776-
heap_freetuple(tup);
799+
ExecStoreVirtualTuple(slot[slotCount]);
800+
slotCount++;
801+
802+
/*
803+
* If slots are full or the end of processing has been reached, insert
804+
* a batch of tuples.
805+
*/
806+
if (slotCount==nslots||natts==tupdesc->natts-1)
807+
{
808+
/* fetch index info only when we know we need it */
809+
if (!indstate)
810+
{
811+
indstate=CatalogOpenIndexes(pg_attribute_rel);
812+
close_index= true;
813+
}
814+
815+
/* insert the new tuples and update the indexes */
816+
CatalogTuplesMultiInsertWithInfo(pg_attribute_rel,slot,slotCount,
817+
indstate);
818+
slotCount=0;
819+
}
820+
821+
natts++;
822+
}
823+
824+
if (close_index)
825+
CatalogCloseIndexes(indstate);
826+
for (inti=0;i<nslots;i++)
827+
ExecDropSingleTupleTableSlot(slot[i]);
828+
pfree(slot);
777829
}
778830

779831
/* --------------------------------
@@ -788,8 +840,6 @@ AddNewAttributeTuples(Oid new_rel_oid,
788840
TupleDesctupdesc,
789841
charrelkind)
790842
{
791-
Form_pg_attributeattr;
792-
inti;
793843
Relationrel;
794844
CatalogIndexStateindstate;
795845
intnatts=tupdesc->natts;
@@ -803,30 +853,26 @@ AddNewAttributeTuples(Oid new_rel_oid,
803853

804854
indstate=CatalogOpenIndexes(rel);
805855

806-
/*
807-
* First we add the user attributes. This is also a convenient place to
808-
* add dependencies on their datatypes and collations.
809-
*/
810-
for (i=0;i<natts;i++)
811-
{
812-
attr=TupleDescAttr(tupdesc,i);
813-
/* Fill in the correct relation OID */
814-
attr->attrelid=new_rel_oid;
815-
/* Make sure this is OK, too */
816-
attr->attstattarget=-1;
817-
818-
InsertPgAttributeTuple(rel,attr, (Datum)0,indstate);
856+
/* set stats detail level to a sane default */
857+
for (inti=0;i<natts;i++)
858+
tupdesc->attrs[i].attstattarget=-1;
859+
InsertPgAttributeTuples(rel,tupdesc,new_rel_oid,NULL,indstate);
819860

861+
/* add dependencies on their datatypes and collations */
862+
for (inti=0;i<natts;i++)
863+
{
820864
/* Add dependency info */
821865
ObjectAddressSubSet(myself,RelationRelationId,new_rel_oid,i+1);
822-
ObjectAddressSet(referenced,TypeRelationId,attr->atttypid);
866+
ObjectAddressSet(referenced,TypeRelationId,
867+
tupdesc->attrs[i].atttypid);
823868
recordDependencyOn(&myself,&referenced,DEPENDENCY_NORMAL);
824869

825870
/* The default collation is pinned, so don't bother recording it */
826-
if (OidIsValid(attr->attcollation)&&
827-
attr->attcollation!=DEFAULT_COLLATION_OID)
871+
if (OidIsValid(tupdesc->attrs[i].attcollation)&&
872+
tupdesc->attrs[i].attcollation!=DEFAULT_COLLATION_OID)
828873
{
829-
ObjectAddressSet(referenced,CollationRelationId,attr->attcollation);
874+
ObjectAddressSet(referenced,CollationRelationId,
875+
tupdesc->attrs[i].attcollation);
830876
recordDependencyOn(&myself,&referenced,DEPENDENCY_NORMAL);
831877
}
832878
}
@@ -838,17 +884,12 @@ AddNewAttributeTuples(Oid new_rel_oid,
838884
*/
839885
if (relkind!=RELKIND_VIEW&&relkind!=RELKIND_COMPOSITE_TYPE)
840886
{
841-
for (i=0;i< (int)lengthof(SysAtt);i++)
842-
{
843-
FormData_pg_attributeattStruct;
887+
TupleDesctd;
844888

845-
memcpy(&attStruct,SysAtt[i],sizeof(FormData_pg_attribute));
889+
td=CreateTupleDesc(lengthof(SysAtt),(FormData_pg_attribute**)&SysAtt);
846890

847-
/* Fill in the correct relation OID in the copied tuple */
848-
attStruct.attrelid=new_rel_oid;
849-
850-
InsertPgAttributeTuple(rel,&attStruct, (Datum)0,indstate);
851-
}
891+
InsertPgAttributeTuples(rel,td,new_rel_oid,NULL,indstate);
892+
FreeTupleDesc(td);
852893
}
853894

854895
/*

‎src/backend/catalog/index.c

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,7 @@ static TupleDesc ConstructTupleDescriptor(Relation heapRelation,
106106
Oid*classObjectId);
107107
staticvoidInitializeAttributeOids(RelationindexRelation,
108108
intnumatts,Oidindexoid);
109-
staticvoidAppendAttributeTuples(RelationindexRelation,intnumatts,
110-
Datum*attopts);
109+
staticvoidAppendAttributeTuples(RelationindexRelation,Datum*attopts);
111110
staticvoidUpdateIndexRelation(Oidindexoid,Oidheapoid,
112111
OidparentIndexId,
113112
IndexInfo*indexInfo,
@@ -485,12 +484,11 @@ InitializeAttributeOids(Relation indexRelation,
485484
* ----------------------------------------------------------------
486485
*/
487486
staticvoid
488-
AppendAttributeTuples(RelationindexRelation,intnumatts,Datum*attopts)
487+
AppendAttributeTuples(RelationindexRelation,Datum*attopts)
489488
{
490489
Relationpg_attribute;
491490
CatalogIndexStateindstate;
492491
TupleDescindexTupDesc;
493-
inti;
494492

495493
/*
496494
* open the attribute relation and its indexes
@@ -504,15 +502,7 @@ AppendAttributeTuples(Relation indexRelation, int numatts, Datum *attopts)
504502
*/
505503
indexTupDesc=RelationGetDescr(indexRelation);
506504

507-
for (i=0;i<numatts;i++)
508-
{
509-
Form_pg_attributeattr=TupleDescAttr(indexTupDesc,i);
510-
Datumattoptions=attopts ?attopts[i] : (Datum)0;
511-
512-
Assert(attr->attnum==i+1);
513-
514-
InsertPgAttributeTuple(pg_attribute,attr,attoptions,indstate);
515-
}
505+
InsertPgAttributeTuples(pg_attribute,indexTupDesc,InvalidOid,attopts,indstate);
516506

517507
CatalogCloseIndexes(indstate);
518508

@@ -979,8 +969,7 @@ index_create(Relation heapRelation,
979969
/*
980970
* append ATTRIBUTE tuples for the index
981971
*/
982-
AppendAttributeTuples(indexRelation,indexInfo->ii_NumIndexAttrs,
983-
indexInfo->ii_OpclassOptions);
972+
AppendAttributeTuples(indexRelation,indexInfo->ii_OpclassOptions);
984973

985974
/* ----------------
986975
* update pg_index

‎src/backend/catalog/indexing.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include"access/genam.h"
1919
#include"access/heapam.h"
2020
#include"access/htup_details.h"
21+
#include"access/xact.h"
2122
#include"catalog/index.h"
2223
#include"catalog/indexing.h"
2324
#include"executor/executor.h"
@@ -250,6 +251,41 @@ CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup,
250251
CatalogIndexInsert(indstate,tup);
251252
}
252253

254+
/*
255+
* CatalogTuplesMultiInsertWithInfo - as above, but for multiple tuples
256+
*
257+
* Insert multiple tuples into the given catalog relation at once, with an
258+
* amortized cost of CatalogOpenIndexes.
259+
*/
260+
void
261+
CatalogTuplesMultiInsertWithInfo(RelationheapRel,TupleTableSlot**slot,
262+
intntuples,CatalogIndexStateindstate)
263+
{
264+
/* Nothing to do */
265+
if (ntuples <=0)
266+
return;
267+
268+
heap_multi_insert(heapRel,slot,ntuples,
269+
GetCurrentCommandId(true),0,NULL);
270+
271+
/*
272+
* There is no equivalent to heap_multi_insert for the catalog indexes, so
273+
* we must loop over and insert individually.
274+
*/
275+
for (inti=0;i<ntuples;i++)
276+
{
277+
boolshould_free;
278+
HeapTupletuple;
279+
280+
tuple=ExecFetchSlotHeapTuple(slot[i], true,&should_free);
281+
tuple->t_tableOid=slot[i]->tts_tableOid;
282+
CatalogIndexInsert(indstate,tuple);
283+
284+
if (should_free)
285+
heap_freetuple(tuple);
286+
}
287+
}
288+
253289
/*
254290
* CatalogTupleUpdate - do heap and indexing work for updating a catalog tuple
255291
*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp