Add amgettreeheight index AM API routine
authorPeter Eisentraut <[email protected]>
Tue, 10 Sep 2024 07:51:55 +0000 (09:51 +0200)
committerPeter Eisentraut <[email protected]>
Tue, 10 Sep 2024 08:03:23 +0000 (10:03 +0200)
The only current implementation is for btree where it calls
_bt_getrootheight().  Other index types can now also use this to pass
information to their amcostestimate routine.  Previously, btree was
hardcoded and other index types could not hook into the optimizer at
this point.

Author: Mark Dilger <[email protected]>
Discussion: https://www.postgresql.org/message-id/flat/E72EAA49-354D-4C2E-8EB9-255197F55330@enterprisedb.com

12 files changed:
contrib/bloom/blutils.c
doc/src/sgml/indexam.sgml
src/backend/access/brin/brin.c
src/backend/access/gin/ginutil.c
src/backend/access/gist/gist.c
src/backend/access/hash/hash.c
src/backend/access/nbtree/nbtree.c
src/backend/access/spgist/spgutils.c
src/backend/optimizer/util/plancat.c
src/include/access/amapi.h
src/include/access/nbtree.h
src/test/modules/dummy_index_am/dummy_index_am.c

index 6836129c90d8e2254b16c1a741e1575ecdc4f6a1..a29330afcd399f123065f82f4e05f12b4bdf249c 100644 (file)
@@ -137,6 +137,7 @@ blhandler(PG_FUNCTION_ARGS)
    amroutine->amvacuumcleanup = blvacuumcleanup;
    amroutine->amcanreturn = NULL;
    amroutine->amcostestimate = blcostestimate;
+   amroutine->amgettreeheight = NULL;
    amroutine->amoptions = bloptions;
    amroutine->amproperty = NULL;
    amroutine->ambuildphasename = NULL;
index e3c1539a1e3bc3c621c422d57e03573cd17a0a9e..dc7d14b60dd24ddcd95c0b6c93d3a9464aba9394 100644 (file)
@@ -146,6 +146,7 @@ typedef struct IndexAmRoutine
     amvacuumcleanup_function amvacuumcleanup;
     amcanreturn_function amcanreturn;   /* can be NULL */
     amcostestimate_function amcostestimate;
+    amgettreeheight_function amgettreeheight;   /* can be NULL */
     amoptions_function amoptions;
     amproperty_function amproperty;     /* can be NULL */
     ambuildphasename_function ambuildphasename;   /* can be NULL */
@@ -480,6 +481,21 @@ amcostestimate (PlannerInfo *root,
 
   <para>
 <programlisting>
+int
+amgettreeheight (Relation rel);
+</programlisting>
+   Compute the height of a tree-shaped index.  This information is supplied to
+   the <function>amcostestimate</function> function in
+   <literal>path->indexinfo->tree_height</literal> and can be used to support
+   the cost estimation.  The result is not used anywhere else, so this
+   function can actually be used to compute any kind of data (that fits into
+   an integer) about the index that the cost estimation function might want to
+   know.  If the computation is expensive, it could be useful to cache the
+   result as part of <literal>RelationData.rd_amcache</literal>.
+  </para>
+
+  <para>
+<programlisting>
 bytea *
 amoptions (ArrayType *reloptions,
            bool validate);
index 6467bed604a0511da8ca65850a2dbcff56b34fbf..94a8bd0701743df14eb641b14af39c483dc14915 100644 (file)
@@ -279,6 +279,7 @@ brinhandler(PG_FUNCTION_ARGS)
    amroutine->amvacuumcleanup = brinvacuumcleanup;
    amroutine->amcanreturn = NULL;
    amroutine->amcostestimate = brincostestimate;
+   amroutine->amgettreeheight = NULL;
    amroutine->amoptions = brinoptions;
    amroutine->amproperty = NULL;
    amroutine->ambuildphasename = NULL;
index 5747ae6a4cabe163431f5cd4f738e9e4b9d6c1ba..830d67fbc208a26b1b0b1dd9c825a0275953abe9 100644 (file)
@@ -69,6 +69,7 @@ ginhandler(PG_FUNCTION_ARGS)
    amroutine->amvacuumcleanup = ginvacuumcleanup;
    amroutine->amcanreturn = NULL;
    amroutine->amcostestimate = gincostestimate;
+   amroutine->amgettreeheight = NULL;
    amroutine->amoptions = ginoptions;
    amroutine->amproperty = NULL;
    amroutine->ambuildphasename = NULL;
index ed4ffa63a77208f4548b5ac87162032dd5ee1922..2d7a0687d4a5bfbeae54264cea8b10f95de1aaef 100644 (file)
@@ -91,6 +91,7 @@ gisthandler(PG_FUNCTION_ARGS)
    amroutine->amvacuumcleanup = gistvacuumcleanup;
    amroutine->amcanreturn = gistcanreturn;
    amroutine->amcostestimate = gistcostestimate;
+   amroutine->amgettreeheight = NULL;
    amroutine->amoptions = gistoptions;
    amroutine->amproperty = gistproperty;
    amroutine->ambuildphasename = NULL;
index 01d06b7c3289e0063ca77048a262c789862e3f21..a783b9b4e252fab7adde9d7fe44804ee81054093 100644 (file)
@@ -89,6 +89,7 @@ hashhandler(PG_FUNCTION_ARGS)
    amroutine->amvacuumcleanup = hashvacuumcleanup;
    amroutine->amcanreturn = NULL;
    amroutine->amcostestimate = hashcostestimate;
+   amroutine->amgettreeheight = NULL;
    amroutine->amoptions = hashoptions;
    amroutine->amproperty = NULL;
    amroutine->ambuildphasename = NULL;
index 686a3206f726bdf07852ee96b23350c1261ea337..8cfaab949beabc49bcb4cfc0fba3e4f21a8a44a4 100644 (file)
@@ -133,6 +133,7 @@ bthandler(PG_FUNCTION_ARGS)
    amroutine->amvacuumcleanup = btvacuumcleanup;
    amroutine->amcanreturn = btcanreturn;
    amroutine->amcostestimate = btcostestimate;
+   amroutine->amgettreeheight = btgettreeheight;
    amroutine->amoptions = btoptions;
    amroutine->amproperty = btproperty;
    amroutine->ambuildphasename = btbuildphasename;
@@ -1445,3 +1446,12 @@ btcanreturn(Relation index, int attno)
 {
    return true;
 }
+
+/*
+ * btgettreeheight() -- Compute tree height for use by btcostestimate().
+ */
+int
+btgettreeheight(Relation rel)
+{
+   return _bt_getrootheight(rel);
+}
index 76b80146ff01b7a5f99a4cfce0ebfc3190067441..72b7661971fb57d2575f91cea9fa933d99b8de7c 100644 (file)
@@ -76,6 +76,7 @@ spghandler(PG_FUNCTION_ARGS)
    amroutine->amvacuumcleanup = spgvacuumcleanup;
    amroutine->amcanreturn = spgcanreturn;
    amroutine->amcostestimate = spgcostestimate;
+   amroutine->amgettreeheight = NULL;
    amroutine->amoptions = spgoptions;
    amroutine->amproperty = spgproperty;
    amroutine->ambuildphasename = NULL;
index 78a3cfafde4e21c43ddcb7e2e0c904958e777021..82f031f4cfe83eae2d957105a2a48337bad3a9e7 100644 (file)
@@ -241,7 +241,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
            Oid         indexoid = lfirst_oid(l);
            Relation    indexRelation;
            Form_pg_index index;
-           IndexAmRoutine *amroutine;
+           IndexAmRoutine *amroutine = NULL;
            IndexOptInfo *info;
            int         ncolumns,
                        nkeycolumns;
@@ -485,13 +485,12 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
                        info->tuples = rel->tuples;
                }
 
-               if (info->relam == BTREE_AM_OID)
+               /*
+                * Get tree height while we have the index open
+                */
+               if (amroutine->amgettreeheight)
                {
-                   /*
-                    * For btrees, get tree height while we have the index
-                    * open
-                    */
-                   info->tree_height = _bt_getrootheight(indexRelation);
+                   info->tree_height = amroutine->amgettreeheight(indexRelation);
                }
                else
                {
index f25c9d58a7daadc0f4c04a4da4391fde09467566..c51de742ea03dc1660834e21232a8a00ae071cb8 100644 (file)
@@ -140,6 +140,13 @@ typedef void (*amcostestimate_function) (struct PlannerInfo *root,
                                         double *indexCorrelation,
                                         double *indexPages);
 
+/* estimate height of a tree-structured index
+ *
+ * XXX This just computes a value that is later used by amcostestimate.  This
+ * API could be expanded to support passing more values if the need arises.
+ */
+typedef int (*amgettreeheight_function) (Relation rel);
+
 /* parse index reloptions */
 typedef bytea *(*amoptions_function) (Datum reloptions,
                                      bool validate);
@@ -272,6 +279,7 @@ typedef struct IndexAmRoutine
    amvacuumcleanup_function amvacuumcleanup;
    amcanreturn_function amcanreturn;   /* can be NULL */
    amcostestimate_function amcostestimate;
+   amgettreeheight_function amgettreeheight;   /* can be NULL */
    amoptions_function amoptions;
    amproperty_function amproperty; /* can be NULL */
    ambuildphasename_function ambuildphasename; /* can be NULL */
index 9af9b3ecdccec351e15a2279ef868073e86b8f7b..d64300fb97388f7585632653c732a0253adee315 100644 (file)
@@ -1186,6 +1186,7 @@ extern IndexBulkDeleteResult *btbulkdelete(IndexVacuumInfo *info,
 extern IndexBulkDeleteResult *btvacuumcleanup(IndexVacuumInfo *info,
                                              IndexBulkDeleteResult *stats);
 extern bool btcanreturn(Relation index, int attno);
+extern int btgettreeheight(Relation rel);
 
 /*
  * prototypes for internal functions in nbtree.c
index 0b4771160672d9e4b706284bc01354fb91680d90..2841cf2eb4bc5a0e63efec9b399477d2a08e094b 100644 (file)
@@ -308,6 +308,7 @@ dihandler(PG_FUNCTION_ARGS)
    amroutine->amvacuumcleanup = divacuumcleanup;
    amroutine->amcanreturn = NULL;
    amroutine->amcostestimate = dicostestimate;
+   amroutine->amgettreeheight = NULL;
    amroutine->amoptions = dioptions;
    amroutine->amproperty = NULL;
    amroutine->ambuildphasename = NULL;