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

Commitdd16b7a

Browse files
committed
Get rid of cluster.c's apparatus for rebuilding a relation's indexes
in favor of using the REINDEX TABLE apparatus, which does the same thingsimpler and faster. Also, make TRUNCATE not use cluster.c at all, butjust assign a new relfilenode and REINDEX. This partially addressesHartmut Raschick's complaint from last December that 7.4's TRUNCATE isan order of magnitude slower than prior releases. By getting rid ofa lot of unnecessary catalog updates, these changes buy back about afactor of two (on my system). The remaining overhead seems associatedwith creating and deleting storage files, which we may not be able todo much about without abandoning transaction safety for TRUNCATE.
1 parent7c6baad commitdd16b7a

File tree

6 files changed

+161
-262
lines changed

6 files changed

+161
-262
lines changed

‎src/backend/catalog/index.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.229 2004/05/05 04:48:45 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.230 2004/05/08 00:34:49 tgl Exp $
1212
*
1313
*
1414
* INTERFACE ROUTINES
@@ -1729,12 +1729,13 @@ reindex_index(Oid indexId)
17291729

17301730
/*
17311731
* reindex_relation - This routine is used to recreate all indexes
1732-
* of a relation (and its toast relation too, if any).
1732+
* of a relation (andoptionallyits toast relation too, if any).
17331733
*
1734-
* Returns true if any indexes were rebuilt.
1734+
* Returns true if any indexes were rebuilt. Note that a
1735+
* CommandCounterIncrement will occur after each index rebuild.
17351736
*/
17361737
bool
1737-
reindex_relation(Oidrelid)
1738+
reindex_relation(Oidrelid,booltoast_too)
17381739
{
17391740
Relationrel;
17401741
Oidtoast_relid;
@@ -1810,8 +1811,8 @@ reindex_relation(Oid relid)
18101811
* If the relation has a secondary toast rel, reindex that too while we
18111812
* still hold the lock on the master table.
18121813
*/
1813-
if (toast_relid!=InvalidOid)
1814-
result |=reindex_relation(toast_relid);
1814+
if (toast_too&&OidIsValid(toast_relid))
1815+
result |=reindex_relation(toast_relid, false);
18151816

18161817
returnresult;
18171818
}

‎src/backend/commands/cluster.c

Lines changed: 87 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
*
1313
* IDENTIFICATION
14-
* $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.122 2004/05/06 16:10:57 tgl Exp $
14+
* $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.123 2004/05/08 00:34:49 tgl Exp $
1515
*
1616
*-------------------------------------------------------------------------
1717
*/
@@ -37,20 +37,6 @@
3737
#include"utils/relcache.h"
3838

3939

40-
/*
41-
* We need one of these structs for each index in the relation to be
42-
* clustered. It's basically the data needed by index_create() so
43-
* we can rebuild the indexes on the new heap.
44-
*/
45-
typedefstruct
46-
{
47-
OidindexOID;
48-
char*indexName;
49-
IndexInfo*indexInfo;
50-
OidaccessMethodOID;
51-
Oid*classOID;
52-
}IndexAttrs;
53-
5440
/*
5541
* This struct is used to pass around the information on tables to be
5642
* clustered. We need this so we can make a list of them when invoked without
@@ -64,6 +50,7 @@ typedef struct
6450

6551

6652
staticvoidcluster_rel(RelToCluster*rv,boolrecheck);
53+
staticvoidrebuild_relation(RelationOldHeap,OidindexOid);
6754
staticvoidcopy_heap_data(OidOIDNewHeap,OidOIDOldHeap,OidOIDOldIndex);
6855
staticList*get_tables_to_cluster(MemoryContextcluster_context);
6956

@@ -411,30 +398,99 @@ check_index_is_clusterable(Relation OldHeap, Oid indexOid)
411398
}
412399

413400
/*
414-
*rebuild_relation: rebuild an existing relation
401+
*mark_index_clustered: mark the specified index as the one clustered on
415402
*
416-
* This is shared code between CLUSTER and TRUNCATE. In the TRUNCATE
417-
* case, the new relation is built and left empty.In the CLUSTER case,
418-
* it is filled with data read from the old relation in the order specified
419-
* by the index.
403+
* With indexOid == InvalidOid, will mark all indexes of rel not-clustered.
404+
*/
405+
void
406+
mark_index_clustered(Relationrel,OidindexOid)
407+
{
408+
HeapTupleindexTuple;
409+
Form_pg_indexindexForm;
410+
Relationpg_index;
411+
List*index;
412+
413+
/*
414+
* If the index is already marked clustered, no need to do anything.
415+
*/
416+
if (OidIsValid(indexOid))
417+
{
418+
indexTuple=SearchSysCache(INDEXRELID,
419+
ObjectIdGetDatum(indexOid),
420+
0,0,0);
421+
if (!HeapTupleIsValid(indexTuple))
422+
elog(ERROR,"cache lookup failed for index %u",indexOid);
423+
indexForm= (Form_pg_index)GETSTRUCT(indexTuple);
424+
425+
if (indexForm->indisclustered)
426+
{
427+
ReleaseSysCache(indexTuple);
428+
return;
429+
}
430+
431+
ReleaseSysCache(indexTuple);
432+
}
433+
434+
/*
435+
* Check each index of the relation and set/clear the bit as needed.
436+
*/
437+
pg_index=heap_openr(IndexRelationName,RowExclusiveLock);
438+
439+
foreach(index,RelationGetIndexList(rel))
440+
{
441+
OidthisIndexOid=lfirsto(index);
442+
443+
indexTuple=SearchSysCacheCopy(INDEXRELID,
444+
ObjectIdGetDatum(thisIndexOid),
445+
0,0,0);
446+
if (!HeapTupleIsValid(indexTuple))
447+
elog(ERROR,"cache lookup failed for index %u",thisIndexOid);
448+
indexForm= (Form_pg_index)GETSTRUCT(indexTuple);
449+
450+
/*
451+
* Unset the bit if set. We know it's wrong because we checked
452+
* this earlier.
453+
*/
454+
if (indexForm->indisclustered)
455+
{
456+
indexForm->indisclustered= false;
457+
simple_heap_update(pg_index,&indexTuple->t_self,indexTuple);
458+
CatalogUpdateIndexes(pg_index,indexTuple);
459+
/* Ensure we see the update in the index's relcache entry */
460+
CacheInvalidateRelcacheByRelid(thisIndexOid);
461+
}
462+
elseif (thisIndexOid==indexOid)
463+
{
464+
indexForm->indisclustered= true;
465+
simple_heap_update(pg_index,&indexTuple->t_self,indexTuple);
466+
CatalogUpdateIndexes(pg_index,indexTuple);
467+
/* Ensure we see the update in the index's relcache entry */
468+
CacheInvalidateRelcacheByRelid(thisIndexOid);
469+
}
470+
heap_freetuple(indexTuple);
471+
}
472+
473+
heap_close(pg_index,RowExclusiveLock);
474+
}
475+
476+
/*
477+
* rebuild_relation: rebuild an existing relation in index order
420478
*
421479
* OldHeap: table to rebuild --- must be opened and exclusive-locked!
422-
* indexOid: index to cluster by, or InvalidOid in TRUNCATE case
480+
* indexOid: index to cluster by
423481
*
424482
* NB: this routine closes OldHeap at the right time; caller should not.
425483
*/
426-
void
484+
staticvoid
427485
rebuild_relation(RelationOldHeap,OidindexOid)
428486
{
429487
OidtableOid=RelationGetRelid(OldHeap);
430-
OidoldClusterIndex;
431-
List*indexes;
432488
OidOIDNewHeap;
433489
charNewHeapName[NAMEDATALEN];
434490
ObjectAddressobject;
435491

436-
/*Save theinformation about all indexes on the relation. */
437-
indexes=get_indexattr_list(OldHeap,&oldClusterIndex);
492+
/*Mark thecorrect index as clustered */
493+
mark_index_clustered(OldHeap,indexOid);
438494

439495
/* Close relcache entry, but keep lock until transaction commit */
440496
heap_close(OldHeap,NoLock);
@@ -459,8 +515,7 @@ rebuild_relation(Relation OldHeap, Oid indexOid)
459515
/*
460516
* Copy the heap data into the new table in the desired order.
461517
*/
462-
if (OidIsValid(indexOid))
463-
copy_heap_data(OIDNewHeap,tableOid,indexOid);
518+
copy_heap_data(OIDNewHeap,tableOid,indexOid);
464519

465520
/* To make the new heap's data visible (probably not needed?). */
466521
CommandCounterIncrement();
@@ -484,11 +539,11 @@ rebuild_relation(Relation OldHeap, Oid indexOid)
484539
/* performDeletion does CommandCounterIncrement at end */
485540

486541
/*
487-
* Recreate each index on the relation. We do not need
488-
* CommandCounterIncrement() because rebuild_indexes does it.
542+
* Rebuild each index on the relation (but not the toast table,
543+
* which is all-new at this point). We do not need
544+
* CommandCounterIncrement() because reindex_relation does it.
489545
*/
490-
rebuild_indexes(tableOid,indexes,
491-
(OidIsValid(indexOid) ?indexOid :oldClusterIndex));
546+
reindex_relation(tableOid, false);
492547
}
493548

494549
/*
@@ -589,138 +644,6 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
589644
heap_close(NewHeap,NoLock);
590645
}
591646

592-
/*
593-
* Get the necessary info about the indexes of the relation and
594-
* return a list of IndexAttrs structures. Also, *OldClusterIndex
595-
* is set to the OID of the existing clustered index, or InvalidOid
596-
* if there is none.
597-
*/
598-
List*
599-
get_indexattr_list(RelationOldHeap,Oid*OldClusterIndex)
600-
{
601-
List*indexes=NIL;
602-
List*indlist;
603-
604-
*OldClusterIndex=InvalidOid;
605-
606-
/* Ask the relcache to produce a list of the indexes of the old rel */
607-
foreach(indlist,RelationGetIndexList(OldHeap))
608-
{
609-
OidindexOID=lfirsto(indlist);
610-
RelationoldIndex;
611-
IndexAttrs*attrs;
612-
613-
oldIndex=index_open(indexOID);
614-
615-
attrs= (IndexAttrs*)palloc(sizeof(IndexAttrs));
616-
attrs->indexOID=indexOID;
617-
attrs->indexName=pstrdup(NameStr(oldIndex->rd_rel->relname));
618-
attrs->accessMethodOID=oldIndex->rd_rel->relam;
619-
attrs->indexInfo=BuildIndexInfo(oldIndex);
620-
attrs->classOID= (Oid*)
621-
palloc(sizeof(Oid)*attrs->indexInfo->ii_NumIndexAttrs);
622-
memcpy(attrs->classOID,oldIndex->rd_index->indclass,
623-
sizeof(Oid)*attrs->indexInfo->ii_NumIndexAttrs);
624-
if (oldIndex->rd_index->indisclustered)
625-
*OldClusterIndex=indexOID;
626-
627-
index_close(oldIndex);
628-
629-
indexes=lappend(indexes,attrs);
630-
}
631-
632-
returnindexes;
633-
}
634-
635-
/*
636-
* Create new indexes and swap the filenodes with old indexes.Then drop
637-
* the new index (carrying the old index filenode along).
638-
*
639-
* OIDClusterIndex is the OID of the index to be marked as clustered, or
640-
* InvalidOid if none should be marked clustered.
641-
*/
642-
void
643-
rebuild_indexes(OidOIDOldHeap,List*indexes,OidOIDClusterIndex)
644-
{
645-
List*elem;
646-
647-
foreach(elem,indexes)
648-
{
649-
IndexAttrs*attrs= (IndexAttrs*)lfirst(elem);
650-
OidoldIndexOID=attrs->indexOID;
651-
OidnewIndexOID;
652-
charnewIndexName[NAMEDATALEN];
653-
boolisclustered;
654-
ObjectAddressobject;
655-
Form_pg_indexindex;
656-
HeapTupletuple;
657-
Relationpg_index;
658-
659-
/* Create the new index under a temporary name */
660-
snprintf(newIndexName,sizeof(newIndexName),
661-
"pg_temp_%u",oldIndexOID);
662-
663-
/*
664-
* The new index will have primary and constraint status set to
665-
* false, but since we will only use its filenode it doesn't
666-
* matter: after the filenode swap the index will keep the
667-
* constraint status of the old index.
668-
*/
669-
newIndexOID=index_create(OIDOldHeap,
670-
newIndexName,
671-
attrs->indexInfo,
672-
attrs->accessMethodOID,
673-
attrs->classOID,
674-
false,
675-
false,
676-
allowSystemTableMods,
677-
false);
678-
CommandCounterIncrement();
679-
680-
/* Swap the filenodes. */
681-
swap_relfilenodes(oldIndexOID,newIndexOID);
682-
683-
CommandCounterIncrement();
684-
685-
/*
686-
* Make sure that indisclustered is correct: it should be set only
687-
* for the index specified by the caller.
688-
*/
689-
isclustered= (oldIndexOID==OIDClusterIndex);
690-
691-
pg_index=heap_openr(IndexRelationName,RowExclusiveLock);
692-
tuple=SearchSysCacheCopy(INDEXRELID,
693-
ObjectIdGetDatum(oldIndexOID),
694-
0,0,0);
695-
if (!HeapTupleIsValid(tuple))
696-
elog(ERROR,"cache lookup failed for index %u",oldIndexOID);
697-
index= (Form_pg_index)GETSTRUCT(tuple);
698-
if (index->indisclustered!=isclustered)
699-
{
700-
index->indisclustered=isclustered;
701-
simple_heap_update(pg_index,&tuple->t_self,tuple);
702-
CatalogUpdateIndexes(pg_index,tuple);
703-
/* Ensure we see the update in the index's relcache entry */
704-
CacheInvalidateRelcacheByRelid(oldIndexOID);
705-
}
706-
heap_freetuple(tuple);
707-
heap_close(pg_index,RowExclusiveLock);
708-
709-
/* Destroy new index with old filenode */
710-
object.classId=RelOid_pg_class;
711-
object.objectId=newIndexOID;
712-
object.objectSubId=0;
713-
714-
/*
715-
* The relation is local to our transaction and we know nothing
716-
* depends on it, so DROP_RESTRICT should be OK.
717-
*/
718-
performDeletion(&object,DROP_RESTRICT);
719-
720-
/* performDeletion does CommandCounterIncrement() at its end */
721-
}
722-
}
723-
724647
/*
725648
* Swap the relfilenodes for two given relations.
726649
*

‎src/backend/commands/indexcmds.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.118 2004/05/05 04:48:45 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.119 2004/05/08 00:34:49 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -826,7 +826,7 @@ ReindexTable(RangeVar *relation, bool force /* currently unused */ )
826826

827827
ReleaseSysCache(tuple);
828828

829-
if (!reindex_relation(heapOid))
829+
if (!reindex_relation(heapOid, true))
830830
ereport(NOTICE,
831831
(errmsg("table \"%s\" has no indexes",
832832
relation->relname)));
@@ -936,7 +936,7 @@ ReindexDatabase(const char *dbname, bool force /* currently unused */,
936936
StartTransactionCommand();
937937
SetQuerySnapshot();/* might be needed for functions in
938938
* indexes */
939-
if (reindex_relation(relid))
939+
if (reindex_relation(relid, true))
940940
ereport(NOTICE,
941941
(errmsg("table \"%s\" was reindexed",
942942
get_rel_name(relid))));

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp