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

Commit97903c3

Browse files
committed
Fix a performance problem in databases with large numbers of tables
(or other types of pg_class entry): the function pgstat_vacuum_tabstat,invoked during VACUUM startup, had runtime proportional to the number ofstats table entries times the number of pg_class rows; in other wordsO(N^2) if the stats collector's information is reasonably complete.Replace list searching with a hash table to bring it back to O(N)behavior. Per report from kim at myemma.com.Back-patch as far as 8.1; 8.0 and before use different coding here.
1 parent87f6d64 commit97903c3

File tree

1 file changed

+59
-28
lines changed

1 file changed

+59
-28
lines changed

‎src/backend/postmaster/pgstat.c

Lines changed: 59 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*
1414
*Copyright (c) 2001-2007, PostgreSQL Global Development Group
1515
*
16-
*$PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.142 2007/01/05 22:19:36 momjian Exp $
16+
*$PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.143 2007/01/11 23:06:03 tgl Exp $
1717
* ----------
1818
*/
1919
#include"postgres.h"
@@ -159,6 +159,7 @@ static void pgstat_write_statsfile(void);
159159
staticvoidpgstat_read_statsfile(HTAB**dbhash,Oidonlydb);
160160
staticvoidbackend_read_statsfile(void);
161161
staticvoidpgstat_read_current_status(void);
162+
staticHTAB*pgstat_collect_oids(Oidcatalogid);
162163

163164
staticvoidpgstat_setheader(PgStat_MsgHdr*hdr,StatMsgTypemtype);
164165
staticvoidpgstat_send(void*msg,intlen);
@@ -657,10 +658,7 @@ pgstat_report_tabstat(void)
657658
void
658659
pgstat_vacuum_tabstat(void)
659660
{
660-
List*oidlist;
661-
Relationrel;
662-
HeapScanDescscan;
663-
HeapTupletup;
661+
HTAB*htab;
664662
PgStat_MsgTabpurgemsg;
665663
HASH_SEQ_STATUShstat;
666664
PgStat_StatDBEntry*dbentry;
@@ -679,15 +677,7 @@ pgstat_vacuum_tabstat(void)
679677
/*
680678
* Read pg_database and make a list of OIDs of all existing databases
681679
*/
682-
oidlist=NIL;
683-
rel=heap_open(DatabaseRelationId,AccessShareLock);
684-
scan=heap_beginscan(rel,SnapshotNow,0,NULL);
685-
while ((tup=heap_getnext(scan,ForwardScanDirection))!=NULL)
686-
{
687-
oidlist=lappend_oid(oidlist,HeapTupleGetOid(tup));
688-
}
689-
heap_endscan(scan);
690-
heap_close(rel,AccessShareLock);
680+
htab=pgstat_collect_oids(DatabaseRelationId);
691681

692682
/*
693683
* Search the database hash table for dead databases and tell the
@@ -698,12 +688,14 @@ pgstat_vacuum_tabstat(void)
698688
{
699689
Oiddbid=dbentry->databaseid;
700690

701-
if (!list_member_oid(oidlist,dbid))
691+
CHECK_FOR_INTERRUPTS();
692+
693+
if (hash_search(htab, (void*)&dbid,HASH_FIND,NULL)==NULL)
702694
pgstat_drop_database(dbid);
703695
}
704696

705697
/* Clean up */
706-
list_free(oidlist);
698+
hash_destroy(htab);
707699

708700
/*
709701
* Lookup our own database entry; if not found, nothing more to do.
@@ -717,15 +709,7 @@ pgstat_vacuum_tabstat(void)
717709
/*
718710
* Similarly to above, make a list of all known relations in this DB.
719711
*/
720-
oidlist=NIL;
721-
rel=heap_open(RelationRelationId,AccessShareLock);
722-
scan=heap_beginscan(rel,SnapshotNow,0,NULL);
723-
while ((tup=heap_getnext(scan,ForwardScanDirection))!=NULL)
724-
{
725-
oidlist=lappend_oid(oidlist,HeapTupleGetOid(tup));
726-
}
727-
heap_endscan(scan);
728-
heap_close(rel,AccessShareLock);
712+
htab=pgstat_collect_oids(RelationRelationId);
729713

730714
/*
731715
* Initialize our messages table counter to zero
@@ -738,13 +722,17 @@ pgstat_vacuum_tabstat(void)
738722
hash_seq_init(&hstat,dbentry->tables);
739723
while ((tabentry= (PgStat_StatTabEntry*)hash_seq_search(&hstat))!=NULL)
740724
{
741-
if (list_member_oid(oidlist,tabentry->tableid))
725+
Oidtabid=tabentry->tableid;
726+
727+
CHECK_FOR_INTERRUPTS();
728+
729+
if (hash_search(htab, (void*)&tabid,HASH_FIND,NULL)!=NULL)
742730
continue;
743731

744732
/*
745733
* Not there, so add this table's Oid to the message
746734
*/
747-
msg.m_tableid[msg.m_nentries++]=tabentry->tableid;
735+
msg.m_tableid[msg.m_nentries++]=tabid;
748736

749737
/*
750738
* If the message is full, send it out and reinitialize to empty
@@ -776,7 +764,50 @@ pgstat_vacuum_tabstat(void)
776764
}
777765

778766
/* Clean up */
779-
list_free(oidlist);
767+
hash_destroy(htab);
768+
}
769+
770+
771+
/* ----------
772+
* pgstat_collect_oids() -
773+
*
774+
*Collect the OIDs of either all databases or all tables, according to
775+
*the parameter, into a temporary hash table. Caller should hash_destroy
776+
*the result when done with it.
777+
* ----------
778+
*/
779+
staticHTAB*
780+
pgstat_collect_oids(Oidcatalogid)
781+
{
782+
HTAB*htab;
783+
HASHCTLhash_ctl;
784+
Relationrel;
785+
HeapScanDescscan;
786+
HeapTupletup;
787+
788+
memset(&hash_ctl,0,sizeof(hash_ctl));
789+
hash_ctl.keysize=sizeof(Oid);
790+
hash_ctl.entrysize=sizeof(Oid);
791+
hash_ctl.hash=oid_hash;
792+
htab=hash_create("Temporary table of OIDs",
793+
PGSTAT_TAB_HASH_SIZE,
794+
&hash_ctl,
795+
HASH_ELEM |HASH_FUNCTION);
796+
797+
rel=heap_open(catalogid,AccessShareLock);
798+
scan=heap_beginscan(rel,SnapshotNow,0,NULL);
799+
while ((tup=heap_getnext(scan,ForwardScanDirection))!=NULL)
800+
{
801+
Oidthisoid=HeapTupleGetOid(tup);
802+
803+
CHECK_FOR_INTERRUPTS();
804+
805+
(void)hash_search(htab, (void*)&thisoid,HASH_ENTER,NULL);
806+
}
807+
heap_endscan(scan);
808+
heap_close(rel,AccessShareLock);
809+
810+
returnhtab;
780811
}
781812

782813

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp