Add an index on pg_inherits.inhparent, and use it to avoid seqscans in
find_inheritance_children(). This is a complete no-op in databases without any inheritance. In databases where there are just a few entries in pg_inherits, it could conceivably be a small loss. However, in databases with many inheritance parents, it can be a big win.
This commit is contained in:
parent
649b5ec7c8
commit
540e69a061
@ -13,13 +13,15 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_inherits.c,v 1.3 2009/06/11 14:48:55 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/catalog/pg_inherits.c,v 1.4 2009/12/29 22:00:12 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "access/genam.h"
|
||||||
#include "access/heapam.h"
|
#include "access/heapam.h"
|
||||||
|
#include "catalog/indexing.h"
|
||||||
#include "catalog/pg_class.h"
|
#include "catalog/pg_class.h"
|
||||||
#include "catalog/pg_inherits.h"
|
#include "catalog/pg_inherits.h"
|
||||||
#include "catalog/pg_inherits_fn.h"
|
#include "catalog/pg_inherits_fn.h"
|
||||||
@ -29,6 +31,8 @@
|
|||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
#include "utils/tqual.h"
|
#include "utils/tqual.h"
|
||||||
|
|
||||||
|
static int oid_cmp(const void *p1, const void *p2);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* find_inheritance_children
|
* find_inheritance_children
|
||||||
@ -46,10 +50,14 @@ find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
|
|||||||
{
|
{
|
||||||
List *list = NIL;
|
List *list = NIL;
|
||||||
Relation relation;
|
Relation relation;
|
||||||
HeapScanDesc scan;
|
SysScanDesc scan;
|
||||||
ScanKeyData key[1];
|
ScanKeyData key[1];
|
||||||
HeapTuple inheritsTuple;
|
HeapTuple inheritsTuple;
|
||||||
Oid inhrelid;
|
Oid inhrelid;
|
||||||
|
Oid *oidarr;
|
||||||
|
int maxoids,
|
||||||
|
numoids,
|
||||||
|
i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Can skip the scan if pg_class shows the relation has never had a
|
* Can skip the scan if pg_class shows the relation has never had a
|
||||||
@ -59,21 +67,52 @@ find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
|
|||||||
return NIL;
|
return NIL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX might be a good idea to create an index on pg_inherits' inhparent
|
* Scan pg_inherits and build a working array of subclass OIDs.
|
||||||
* field, so that we can use an indexscan instead of sequential scan here.
|
|
||||||
* However, in typical databases pg_inherits won't have enough entries to
|
|
||||||
* justify an indexscan...
|
|
||||||
*/
|
*/
|
||||||
|
maxoids = 32;
|
||||||
|
oidarr = (Oid *) palloc(maxoids * sizeof(Oid));
|
||||||
|
numoids = 0;
|
||||||
|
|
||||||
relation = heap_open(InheritsRelationId, AccessShareLock);
|
relation = heap_open(InheritsRelationId, AccessShareLock);
|
||||||
|
|
||||||
ScanKeyInit(&key[0],
|
ScanKeyInit(&key[0],
|
||||||
Anum_pg_inherits_inhparent,
|
Anum_pg_inherits_inhparent,
|
||||||
BTEqualStrategyNumber, F_OIDEQ,
|
BTEqualStrategyNumber, F_OIDEQ,
|
||||||
ObjectIdGetDatum(parentrelId));
|
ObjectIdGetDatum(parentrelId));
|
||||||
scan = heap_beginscan(relation, SnapshotNow, 1, key);
|
|
||||||
|
|
||||||
while ((inheritsTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
scan = systable_beginscan(relation, InheritsParentIndexId, true,
|
||||||
|
SnapshotNow, 1, key);
|
||||||
|
|
||||||
|
while ((inheritsTuple = systable_getnext(scan)) != NULL)
|
||||||
{
|
{
|
||||||
inhrelid = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhrelid;
|
inhrelid = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhrelid;
|
||||||
|
if (numoids >= maxoids)
|
||||||
|
{
|
||||||
|
maxoids *= 2;
|
||||||
|
oidarr = (Oid *) repalloc(oidarr, maxoids * sizeof(Oid));
|
||||||
|
}
|
||||||
|
oidarr[numoids++] = inhrelid;
|
||||||
|
}
|
||||||
|
|
||||||
|
systable_endscan(scan);
|
||||||
|
|
||||||
|
heap_close(relation, AccessShareLock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we found more than one child, sort them by OID. This ensures
|
||||||
|
* reasonably consistent behavior regardless of the vagaries of an
|
||||||
|
* indexscan. This is important since we need to be sure all backends
|
||||||
|
* lock children in the same order to avoid needless deadlocks.
|
||||||
|
*/
|
||||||
|
if (numoids > 1)
|
||||||
|
qsort(oidarr, numoids, sizeof(Oid), oid_cmp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Acquire locks and build the result list.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < numoids; i++)
|
||||||
|
{
|
||||||
|
inhrelid = oidarr[i];
|
||||||
|
|
||||||
if (lockmode != NoLock)
|
if (lockmode != NoLock)
|
||||||
{
|
{
|
||||||
@ -99,8 +138,7 @@ find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
|
|||||||
list = lappend_oid(list, inhrelid);
|
list = lappend_oid(list, inhrelid);
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_endscan(scan);
|
pfree(oidarr);
|
||||||
heap_close(relation, AccessShareLock);
|
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
@ -231,7 +269,7 @@ typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
|
|||||||
{
|
{
|
||||||
Oid this_relid = lfirst_oid(queue_item);
|
Oid this_relid = lfirst_oid(queue_item);
|
||||||
ScanKeyData skey;
|
ScanKeyData skey;
|
||||||
HeapScanDesc inhscan;
|
SysScanDesc inhscan;
|
||||||
HeapTuple inhtup;
|
HeapTuple inhtup;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -255,9 +293,10 @@ typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
|
|||||||
BTEqualStrategyNumber, F_OIDEQ,
|
BTEqualStrategyNumber, F_OIDEQ,
|
||||||
ObjectIdGetDatum(this_relid));
|
ObjectIdGetDatum(this_relid));
|
||||||
|
|
||||||
inhscan = heap_beginscan(inhrel, SnapshotNow, 1, &skey);
|
inhscan = systable_beginscan(inhrel, InheritsRelidSeqnoIndexId, true,
|
||||||
|
SnapshotNow, 1, &skey);
|
||||||
|
|
||||||
while ((inhtup = heap_getnext(inhscan, ForwardScanDirection)) != NULL)
|
while ((inhtup = systable_getnext(inhscan)) != NULL)
|
||||||
{
|
{
|
||||||
Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(inhtup);
|
Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(inhtup);
|
||||||
Oid inhparent = inh->inhparent;
|
Oid inhparent = inh->inhparent;
|
||||||
@ -273,7 +312,7 @@ typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
|
|||||||
queue = lappend_oid(queue, inhparent);
|
queue = lappend_oid(queue, inhparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_endscan(inhscan);
|
systable_endscan(inhscan);
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
break;
|
break;
|
||||||
@ -287,3 +326,18 @@ typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* qsort comparison function */
|
||||||
|
static int
|
||||||
|
oid_cmp(const void *p1, const void *p2)
|
||||||
|
{
|
||||||
|
Oid v1 = *((const Oid *) p1);
|
||||||
|
Oid v2 = *((const Oid *) p2);
|
||||||
|
|
||||||
|
if (v1 < v2)
|
||||||
|
return -1;
|
||||||
|
if (v1 > v2)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.311 2009/12/23 16:43:43 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.312 2009/12/29 22:00:12 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1793,8 +1793,8 @@ StoreCatalogInheritance1(Oid relationId, Oid parentOid,
|
|||||||
int16 seqNumber, Relation inhRelation)
|
int16 seqNumber, Relation inhRelation)
|
||||||
{
|
{
|
||||||
TupleDesc desc = RelationGetDescr(inhRelation);
|
TupleDesc desc = RelationGetDescr(inhRelation);
|
||||||
Datum datum[Natts_pg_inherits];
|
Datum values[Natts_pg_inherits];
|
||||||
bool nullarr[Natts_pg_inherits];
|
bool nulls[Natts_pg_inherits];
|
||||||
ObjectAddress childobject,
|
ObjectAddress childobject,
|
||||||
parentobject;
|
parentobject;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
@ -1802,15 +1802,13 @@ StoreCatalogInheritance1(Oid relationId, Oid parentOid,
|
|||||||
/*
|
/*
|
||||||
* Make the pg_inherits entry
|
* Make the pg_inherits entry
|
||||||
*/
|
*/
|
||||||
datum[0] = ObjectIdGetDatum(relationId); /* inhrelid */
|
values[Anum_pg_inherits_inhrelid - 1] = ObjectIdGetDatum(relationId);
|
||||||
datum[1] = ObjectIdGetDatum(parentOid); /* inhparent */
|
values[Anum_pg_inherits_inhparent - 1] = ObjectIdGetDatum(parentOid);
|
||||||
datum[2] = Int16GetDatum(seqNumber); /* inhseqno */
|
values[Anum_pg_inherits_inhseqno - 1] = Int16GetDatum(seqNumber);
|
||||||
|
|
||||||
nullarr[0] = false;
|
memset(nulls, 0, sizeof(nulls));
|
||||||
nullarr[1] = false;
|
|
||||||
nullarr[2] = false;
|
|
||||||
|
|
||||||
tuple = heap_form_tuple(desc, datum, nullarr);
|
tuple = heap_form_tuple(desc, values, nulls);
|
||||||
|
|
||||||
simple_heap_insert(inhRelation, tuple);
|
simple_heap_insert(inhRelation, tuple);
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.562 2009/12/29 20:11:45 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.563 2009/12/29 22:00:14 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -53,6 +53,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 200912281
|
#define CATALOG_VERSION_NO 200912291
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.112 2009/12/29 20:11:45 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.113 2009/12/29 22:00:14 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -156,6 +156,9 @@ DECLARE_UNIQUE_INDEX(pg_index_indexrelid_index, 2679, on pg_index using btree(in
|
|||||||
|
|
||||||
DECLARE_UNIQUE_INDEX(pg_inherits_relid_seqno_index, 2680, on pg_inherits using btree(inhrelid oid_ops, inhseqno int4_ops));
|
DECLARE_UNIQUE_INDEX(pg_inherits_relid_seqno_index, 2680, on pg_inherits using btree(inhrelid oid_ops, inhseqno int4_ops));
|
||||||
#define InheritsRelidSeqnoIndexId 2680
|
#define InheritsRelidSeqnoIndexId 2680
|
||||||
|
/* This following index is not used for a cache and is not unique */
|
||||||
|
DECLARE_INDEX(pg_inherits_parent_index, 2187, on pg_inherits using btree(inhparent oid_ops));
|
||||||
|
#define InheritsParentIndexId 2187
|
||||||
|
|
||||||
DECLARE_UNIQUE_INDEX(pg_language_name_index, 2681, on pg_language using btree(lanname name_ops));
|
DECLARE_UNIQUE_INDEX(pg_language_name_index, 2681, on pg_language using btree(lanname name_ops));
|
||||||
#define LanguageNameIndexId 2681
|
#define LanguageNameIndexId 2681
|
||||||
|
Loading…
x
Reference in New Issue
Block a user