Push the responsibility for handling ignore_killed_tuples down into
authorTom Lane
Wed, 7 Dec 2005 19:37:53 +0000 (19:37 +0000)
committerTom Lane
Wed, 7 Dec 2005 19:37:53 +0000 (19:37 +0000)
_bt_checkkeys(), instead of checking it in the top-level nbtree.c routines
as formerly.  This saves a little bit of loop overhead, but more importantly
it lets us skip performing the index key comparisons for dead tuples.

src/backend/access/nbtree/nbtree.c
src/backend/access/nbtree/nbtsearch.c
src/backend/access/nbtree/nbtutils.c
src/include/access/nbtree.h

index 70aca882e6c28671859a9eebec82a10c9a592932..589a49a2cead6a709cd9344b484813d2be5c0a6d 100644 (file)
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.134 2005/11/22 18:17:06 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.135 2005/12/07 19:37:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -288,21 +288,6 @@ btgettuple(PG_FUNCTION_ARGS)
    else
        res = _bt_first(scan, dir);
 
-   /*
-    * Skip killed tuples if asked to.
-    */
-   if (scan->ignore_killed_tuples)
-   {
-       while (res)
-       {
-           offnum = ItemPointerGetOffsetNumber(&(scan->currentItemData));
-           page = BufferGetPage(so->btso_curbuf);
-           if (!ItemIdDeleted(PageGetItemId(page, offnum)))
-               break;
-           res = _bt_next(scan, dir);
-       }
-   }
-
    /*
     * Save heap TID to use it in _bt_restscan.  Then release the read lock on
     * the buffer so that we aren't blocking other backends.
@@ -353,25 +338,6 @@ btgetmulti(PG_FUNCTION_ARGS)
            res = _bt_next(scan, ForwardScanDirection);
        else
            res = _bt_first(scan, ForwardScanDirection);
-
-       /*
-        * Skip killed tuples if asked to.
-        */
-       if (scan->ignore_killed_tuples)
-       {
-           while (res)
-           {
-               Page        page;
-               OffsetNumber offnum;
-
-               offnum = ItemPointerGetOffsetNumber(&(scan->currentItemData));
-               page = BufferGetPage(so->btso_curbuf);
-               if (!ItemIdDeleted(PageGetItemId(page, offnum)))
-                   break;
-               res = _bt_next(scan, ForwardScanDirection);
-           }
-       }
-
        if (!res)
            break;
        /* Save tuple ID, and continue scanning */
@@ -385,9 +351,8 @@ btgetmulti(PG_FUNCTION_ARGS)
     */
    if (res)
    {
-       ((BTScanOpaque) scan->opaque)->curHeapIptr = scan->xs_ctup.t_self;
-       LockBuffer(((BTScanOpaque) scan->opaque)->btso_curbuf,
-                  BUFFER_LOCK_UNLOCK);
+       so->curHeapIptr = scan->xs_ctup.t_self;
+       LockBuffer(so->btso_curbuf, BUFFER_LOCK_UNLOCK);
    }
 
    *returned_tids = ntids;
index dd4f500842b37ea57b30f634cd2a6ac9c00f182b..4cd79997292c82ec9d7a741a6cf2857d764f5025 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.98 2005/12/07 18:03:48 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.99 2005/12/07 19:37:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -423,8 +423,6 @@ _bt_next(IndexScanDesc scan, ScanDirection dir)
    Page        page;
    OffsetNumber offnum;
    ItemPointer current;
-   BTItem      btitem;
-   IndexTuple  itup;
    BTScanOpaque so;
    bool        continuescan;
 
@@ -445,13 +443,10 @@ _bt_next(IndexScanDesc scan, ScanDirection dir)
        /* current is the next candidate tuple to return */
        offnum = ItemPointerGetOffsetNumber(current);
        page = BufferGetPage(buf);
-       btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offnum));
-       itup = &btitem->bti_itup;
 
-       if (_bt_checkkeys(scan, itup, dir, &continuescan))
+       if (_bt_checkkeys(scan, page, offnum, dir, &continuescan))
        {
            /* tuple passes all scan key conditions, so return it */
-           scan->xs_ctup.t_self = itup->t_tid;
            return true;
        }
 
@@ -485,8 +480,6 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
    Page        page;
    BTStack     stack;
    OffsetNumber offnum;
-   BTItem      btitem;
-   IndexTuple  itup;
    ItemPointer current;
    BlockNumber blkno;
    StrategyNumber strat;
@@ -848,14 +841,11 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
    /* okay, current item pointer for the scan is right */
    offnum = ItemPointerGetOffsetNumber(current);
    page = BufferGetPage(buf);
-   btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offnum));
-   itup = &btitem->bti_itup;
 
    /* is the first item actually acceptable? */
-   if (_bt_checkkeys(scan, itup, dir, &continuescan))
+   if (_bt_checkkeys(scan, page, offnum, dir, &continuescan))
    {
        /* yes, return it */
-       scan->xs_ctup.t_self = itup->t_tid;
        res = true;
    }
    else if (continuescan)
@@ -1215,8 +1205,6 @@ _bt_endpoint(IndexScanDesc scan, ScanDirection dir)
    OffsetNumber maxoff;
    OffsetNumber start;
    BlockNumber blkno;
-   BTItem      btitem;
-   IndexTuple  itup;
    BTScanOpaque so;
    bool        res;
    bool        continuescan;
@@ -1284,16 +1272,12 @@ _bt_endpoint(IndexScanDesc scan, ScanDirection dir)
        page = BufferGetPage(buf);
    }
 
-   btitem = (BTItem) PageGetItem(page, PageGetItemId(page, start));
-   itup = &(btitem->bti_itup);
-
    /*
     * Okay, we are on the first or last tuple.  Does it pass all the quals?
     */
-   if (_bt_checkkeys(scan, itup, dir, &continuescan))
+   if (_bt_checkkeys(scan, page, start, dir, &continuescan))
    {
        /* yes, return it */
-       scan->xs_ctup.t_self = itup->t_tid;
        res = true;
    }
    else if (continuescan)
index f4c2243943b2c5ffb1f8b216fc592c17cdb11b34..7a18fcf0abbf65161aa5b54c1da81be5d2878f62 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.66 2005/11/22 18:17:06 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.67 2005/12/07 19:37:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -477,30 +477,77 @@ _bt_preprocess_keys(IndexScanDesc scan)
 /*
  * Test whether an indextuple satisfies all the scankey conditions.
  *
+ * If so, copy its TID into scan->xs_ctup.t_self, and return TRUE.
+ * If not, return FALSE (xs_ctup is not changed).
+ *
  * If the tuple fails to pass the qual, we also determine whether there's
  * any need to continue the scan beyond this tuple, and set *continuescan
  * accordingly.  See comments for _bt_preprocess_keys(), above, about how
  * this is done.
+ *
+ * scan: index scan descriptor
+ * page: buffer page containing index tuple
+ * offnum: offset number of index tuple (must be a valid item!)
+ * dir: direction we are scanning in
+ * continuescan: output parameter (will be set correctly in all cases)
  */
 bool
-_bt_checkkeys(IndexScanDesc scan, IndexTuple tuple,
+_bt_checkkeys(IndexScanDesc scan,
+             Page page, OffsetNumber offnum,
              ScanDirection dir, bool *continuescan)
 {
-   BTScanOpaque so = (BTScanOpaque) scan->opaque;
-   int         keysz = so->numberOfKeys;
-   int         ikey;
+   ItemId      iid = PageGetItemId(page, offnum);
+   bool        tuple_valid;
+   BTItem      btitem;
+   IndexTuple  tuple;
    TupleDesc   tupdesc;
+   BTScanOpaque so;
+   int         keysz;
+   int         ikey;
    ScanKey     key;
 
-   *continuescan = true;
+   *continuescan = true;       /* default assumption */
+
+   /*
+    * If the scan specifies not to return killed tuples, then we treat
+    * a killed tuple as not passing the qual.  Most of the time, it's a
+    * win to not bother examining the tuple's index keys, but just return
+    * immediately with continuescan = true to proceed to the next tuple.
+    * However, if this is the last tuple on the page, we should check
+    * the index keys to prevent uselessly advancing to the next page.
+    */
+   if (scan->ignore_killed_tuples && ItemIdDeleted(iid))
+   {
+       /* return immediately if there are more tuples on the page */
+       if (ScanDirectionIsForward(dir))
+       {
+           if (offnum < PageGetMaxOffsetNumber(page))
+               return false;
+       }
+       else
+       {
+           BTPageOpaque opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+
+           if (offnum > P_FIRSTDATAKEY(opaque))
+               return false;
+       }
+       /*
+        * OK, we want to check the keys, but we'll return FALSE even
+        * if the tuple passes the key tests.
+        */
+       tuple_valid = false;
+   }
+   else
+       tuple_valid = true;
 
-   /* If no keys, always scan the whole index */
-   if (keysz == 0)
-       return true;
+   btitem = (BTItem) PageGetItem(page, iid);
+   tuple = &btitem->bti_itup;
 
    IncrIndexProcessed();
 
    tupdesc = RelationGetDescr(scan->indexRelation);
+   so = (BTScanOpaque) scan->opaque;
+   keysz = so->numberOfKeys;
 
    for (key = so->keyData, ikey = 0; ikey < keysz; key++, ikey++)
    {
@@ -592,6 +639,9 @@ _bt_checkkeys(IndexScanDesc scan, IndexTuple tuple,
        }
    }
 
-   /* If we get here, the tuple passes all quals. */
-   return true;
+   /* If we get here, the tuple passes all index quals. */
+   if (tuple_valid)
+       scan->xs_ctup.t_self = tuple->t_tid;
+
+   return tuple_valid;
 }
index 9cd00d554da41c1fef8845b65cda56eb7e4203dc..5a3ec5f1efeddcec56fc91ce4e577e14ffaa48fb 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/access/nbtree.h,v 1.88 2005/11/06 19:29:01 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/access/nbtree.h,v 1.89 2005/12/07 19:37:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -467,8 +467,9 @@ extern ScanKey _bt_mkscankey_nodata(Relation rel);
 extern void _bt_freeskey(ScanKey skey);
 extern void _bt_freestack(BTStack stack);
 extern void _bt_preprocess_keys(IndexScanDesc scan);
-extern bool _bt_checkkeys(IndexScanDesc scan, IndexTuple tuple,
-             ScanDirection dir, bool *continuescan);
+extern bool _bt_checkkeys(IndexScanDesc scan,
+                         Page page, OffsetNumber offnum,
+                         ScanDirection dir, bool *continuescan);
 extern BTItem _bt_formitem(IndexTuple itup);
 
 /*