Minor performance improvement: avoid unnecessary creation/unioning of
authorTom Lane
Wed, 20 Apr 2005 15:48:36 +0000 (15:48 +0000)
committerTom Lane
Wed, 20 Apr 2005 15:48:36 +0000 (15:48 +0000)
bitmaps for multiple indexscans.  Instead just let each indexscan add
TIDs directly into the BitmapOr node's result bitmap.

src/backend/executor/nodeBitmapAnd.c
src/backend/executor/nodeBitmapIndexscan.c
src/backend/executor/nodeBitmapOr.c
src/include/nodes/execnodes.h

index 4af1624012b7b988ba97799f94f01f018c564730..1d5d94fc3f82c9e2b4617a252f0e5bd229acfc58 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/executor/nodeBitmapAnd.c,v 1.1 2005/04/19 22:35:12 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/executor/nodeBitmapAnd.c,v 1.2 2005/04/20 15:48:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -46,6 +46,7 @@ ExecInitBitmapAnd(BitmapAnd *node, EState *estate)
    PlanState **bitmapplanstates;
    int         nplans;
    int         i;
+   ListCell   *l;
    Plan       *initNode;
 
    CXT1_printf("ExecInitBitmapAnd: context is %d\n", CurrentMemoryContext);
@@ -78,10 +79,12 @@ ExecInitBitmapAnd(BitmapAnd *node, EState *estate)
     * call ExecInitNode on each of the plans to be executed and save the
     * results into the array "bitmapplanstates".
     */
-   for (i = 0; i < nplans; i++)
+   i = 0;
+   foreach(l, node->bitmapplans)
    {
-       initNode = (Plan *) list_nth(node->bitmapplans, i);
+       initNode = (Plan *) lfirst(l);
        bitmapplanstates[i] = ExecInitNode(initNode, estate);
+       i++;
    }
 
    return bitmapandstate;
index 3ed03eb7cb89126eb94407cf6023f440416b62f1..0c802ea49b0fd769401de19bc60b04cf315680b9 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/executor/nodeBitmapIndexscan.c,v 1.1 2005/04/19 22:35:12 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/executor/nodeBitmapIndexscan.c,v 1.2 2005/04/20 15:48:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -63,9 +63,21 @@ MultiExecBitmapIndexScan(BitmapIndexScanState *node)
    scandesc = node->biss_ScanDesc;
 
    /*
-    * Prepare result bitmap
+    * Prepare the result bitmap.  Normally we just create a new one to pass
+    * back; however, our parent node is allowed to store a pre-made one
+    * into node->biss_result, in which case we just OR our tuple IDs into
+    * the existing bitmap.  (This saves needing explicit UNION steps.)
     */
-   tbm = tbm_create(work_mem * 1024L);
+   if (node->biss_result)
+   {
+       tbm = node->biss_result;
+       node->biss_result = NULL;       /* reset for next time */
+   }
+   else
+   {
+       /* XXX should we use less than work_mem for this? */
+       tbm = tbm_create(work_mem * 1024L);
+   }
 
    /*
     * Get TIDs from index and insert into bitmap
@@ -271,6 +283,9 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate)
    indexstate->ss.ps.plan = (Plan *) node;
    indexstate->ss.ps.state = estate;
 
+   /* normally we don't make the result bitmap till runtime */
+   indexstate->biss_result = NULL;
+
    /*
     * Miscellaneous initialization
     *
index f4ef17223c8fdbc103009ea7e44b4842ba844a8c..9078855ec331ab99423bee28cb1a8a6ac1e049e8 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/executor/nodeBitmapOr.c,v 1.1 2005/04/19 22:35:12 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/executor/nodeBitmapOr.c,v 1.2 2005/04/20 15:48:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -31,6 +31,7 @@
 #include "executor/execdebug.h"
 #include "executor/instrument.h"
 #include "executor/nodeBitmapOr.h"
+#include "miscadmin.h"
 
 
 /* ----------------------------------------------------------------
@@ -46,6 +47,7 @@ ExecInitBitmapOr(BitmapOr *node, EState *estate)
    PlanState **bitmapplanstates;
    int         nplans;
    int         i;
+   ListCell   *l;
    Plan       *initNode;
 
    CXT1_printf("ExecInitBitmapOr: context is %d\n", CurrentMemoryContext);
@@ -78,10 +80,12 @@ ExecInitBitmapOr(BitmapOr *node, EState *estate)
     * call ExecInitNode on each of the plans to be executed and save the
     * results into the array "bitmapplanstates".
     */
-   for (i = 0; i < nplans; i++)
+   i = 0;
+   foreach(l, node->bitmapplans)
    {
-       initNode = (Plan *) list_nth(node->bitmapplans, i);
+       initNode = (Plan *) lfirst(l);
        bitmapplanstates[i] = ExecInitNode(initNode, estate);
+       i++;
    }
 
    return bitmaporstate;
@@ -128,17 +132,41 @@ MultiExecBitmapOr(BitmapOrState *node)
        PlanState  *subnode = bitmapplans[i];
        TIDBitmap  *subresult;
 
-       subresult = (TIDBitmap *) MultiExecProcNode(subnode);
+       /*
+        * We can special-case BitmapIndexScan children to avoid an
+        * explicit tbm_union step for each child: just pass down the
+        * current result bitmap and let the child OR directly into it.
+        */
+       if (IsA(subnode, BitmapIndexScanState))
+       {
+           if (result == NULL)             /* first subplan */
+           {
+               /* XXX should we use less than work_mem for this? */
+               result = tbm_create(work_mem * 1024L);
+           }
+
+           ((BitmapIndexScanState *) subnode)->biss_result = result;
 
-       if (!subresult || !IsA(subresult, TIDBitmap))
-           elog(ERROR, "unrecognized result from subplan");
+           subresult = (TIDBitmap *) MultiExecProcNode(subnode);
 
-       if (result == NULL)
-           result = subresult;         /* first subplan */
+           if (subresult != result)
+               elog(ERROR, "unrecognized result from subplan");
+       }
        else
        {
-           tbm_union(result, subresult);
-           tbm_free(subresult);
+           /* standard implementation */
+           subresult = (TIDBitmap *) MultiExecProcNode(subnode);
+
+           if (!subresult || !IsA(subresult, TIDBitmap))
+               elog(ERROR, "unrecognized result from subplan");
+
+           if (result == NULL)
+               result = subresult;         /* first subplan */
+           else
+           {
+               tbm_union(result, subresult);
+               tbm_free(subresult);
+           }
        }
    }
 
index a5176c2f9555ef8f476d348fc849ae84c90c7ae3..01c50747620fab3b059b817c82840c3b2c556cc5 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.126 2005/04/19 22:35:17 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.127 2005/04/20 15:48:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -901,6 +901,7 @@ typedef struct IndexScanState
 /* ----------------
  *  BitmapIndexScanState information
  *
+ *     result             bitmap to return output into, or NULL
  *     ScanKeys           Skey structures to scan index rel
  *     NumScanKeys        number of Skey structs
  *     RuntimeKeyInfo     array of exprstates for Skeys
@@ -914,6 +915,7 @@ typedef struct IndexScanState
 typedef struct BitmapIndexScanState
 {
    ScanState   ss;             /* its first field is NodeTag */
+   TIDBitmap  *biss_result;
    ScanKey     biss_ScanKeys;
    int         biss_NumScanKeys;
    ExprState **biss_RuntimeKeyInfo;