From 540e69a0613bad2b6ad15b237a8df27110f4b213 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Tue, 29 Dec 2009 22:00:14 +0000
Subject: [PATCH] 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.

---
 src/backend/catalog/pg_inherits.c | 82 +++++++++++++++++++++++++------
 src/backend/commands/tablecmds.c  | 18 +++----
 src/include/catalog/catversion.h  |  4 +-
 src/include/catalog/indexing.h    |  5 +-
 4 files changed, 82 insertions(+), 27 deletions(-)

diff --git a/src/backend/catalog/pg_inherits.c b/src/backend/catalog/pg_inherits.c
index 8ae368b7413..4106417fb31 100644
--- a/src/backend/catalog/pg_inherits.c
+++ b/src/backend/catalog/pg_inherits.c
@@ -13,13 +13,15 @@
  *
  *
  * 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 "access/genam.h"
 #include "access/heapam.h"
+#include "catalog/indexing.h"
 #include "catalog/pg_class.h"
 #include "catalog/pg_inherits.h"
 #include "catalog/pg_inherits_fn.h"
@@ -29,6 +31,8 @@
 #include "utils/syscache.h"
 #include "utils/tqual.h"
 
+static int	oid_cmp(const void *p1, const void *p2);
+
 
 /*
  * find_inheritance_children
@@ -46,10 +50,14 @@ find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
 {
 	List	   *list = NIL;
 	Relation	relation;
-	HeapScanDesc scan;
+	SysScanDesc scan;
 	ScanKeyData key[1];
 	HeapTuple	inheritsTuple;
 	Oid			inhrelid;
+	Oid		   *oidarr;
+	int			maxoids,
+				numoids,
+				i;
 
 	/*
 	 * 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;
 
 	/*
-	 * XXX might be a good idea to create an index on pg_inherits' inhparent
-	 * 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...
+	 * Scan pg_inherits and build a working array of subclass OIDs.
 	 */
+	maxoids = 32;
+	oidarr = (Oid *) palloc(maxoids * sizeof(Oid));
+	numoids = 0;
+
 	relation = heap_open(InheritsRelationId, AccessShareLock);
+
 	ScanKeyInit(&key[0],
 				Anum_pg_inherits_inhparent,
 				BTEqualStrategyNumber, F_OIDEQ,
 				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;
+		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)
 		{
@@ -99,8 +138,7 @@ find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
 		list = lappend_oid(list, inhrelid);
 	}
 
-	heap_endscan(scan);
-	heap_close(relation, AccessShareLock);
+	pfree(oidarr);
 
 	return list;
 }
@@ -231,7 +269,7 @@ typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
 	{
 		Oid			this_relid = lfirst_oid(queue_item);
 		ScanKeyData skey;
-		HeapScanDesc inhscan;
+		SysScanDesc inhscan;
 		HeapTuple	inhtup;
 
 		/*
@@ -255,9 +293,10 @@ typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
 					BTEqualStrategyNumber, F_OIDEQ,
 					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);
 			Oid			inhparent = inh->inhparent;
@@ -273,7 +312,7 @@ typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
 			queue = lappend_oid(queue, inhparent);
 		}
 
-		heap_endscan(inhscan);
+		systable_endscan(inhscan);
 
 		if (result)
 			break;
@@ -287,3 +326,18 @@ typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
 
 	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;
+}
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 55954738088..0412aaf73f2 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8,7 +8,7 @@
  *
  *
  * 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)
 {
 	TupleDesc	desc = RelationGetDescr(inhRelation);
-	Datum		datum[Natts_pg_inherits];
-	bool		nullarr[Natts_pg_inherits];
+	Datum		values[Natts_pg_inherits];
+	bool		nulls[Natts_pg_inherits];
 	ObjectAddress childobject,
 				parentobject;
 	HeapTuple	tuple;
@@ -1802,15 +1802,13 @@ StoreCatalogInheritance1(Oid relationId, Oid parentOid,
 	/*
 	 * Make the pg_inherits entry
 	 */
-	datum[0] = ObjectIdGetDatum(relationId);	/* inhrelid */
-	datum[1] = ObjectIdGetDatum(parentOid);		/* inhparent */
-	datum[2] = Int16GetDatum(seqNumber);		/* inhseqno */
+	values[Anum_pg_inherits_inhrelid - 1] = ObjectIdGetDatum(relationId);
+	values[Anum_pg_inherits_inhparent - 1] = ObjectIdGetDatum(parentOid);
+	values[Anum_pg_inherits_inhseqno - 1] = Int16GetDatum(seqNumber);
 
-	nullarr[0] = false;
-	nullarr[1] = false;
-	nullarr[2] = false;
+	memset(nulls, 0, sizeof(nulls));
 
-	tuple = heap_form_tuple(desc, datum, nullarr);
+	tuple = heap_form_tuple(desc, values, nulls);
 
 	simple_heap_insert(inhRelation, tuple);
 
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 0c4ce005295..05ee9590260 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * 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 */
-#define CATALOG_VERSION_NO	200912281
+#define CATALOG_VERSION_NO	200912291
 
 #endif
diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h
index a5d93ed4455..a7ab8721c7a 100644
--- a/src/include/catalog/indexing.h
+++ b/src/include/catalog/indexing.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * 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));
 #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));
 #define LanguageNameIndexId  2681
-- 
GitLab