Optimize the case where a btree indexscan has current and mark positions
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 24 Aug 2006 01:18:34 +0000 (01:18 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 24 Aug 2006 01:18:34 +0000 (01:18 +0000)
on the same index page; we can avoid data copying as well as buffer refcount
manipulations in this common case.  Makes for a small but noticeable
improvement in mergejoin speed.

Heikki Linnakangas

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

index 57e3154c137c7f73e8b1cb1275d4ae46589e434e..0f3c5956969a7ef5f0e4924e79e4dee1236c937b 100644 (file)
@@ -392,6 +392,7 @@ btrescan(PG_FUNCTION_ARGS)
                ReleaseBuffer(so->markPos.buf);
                so->markPos.buf = InvalidBuffer;
        }
+       so->markItemIndex = -1;
 
        /*
         * Reset the scan keys. Note that keys ordering stuff moved to _bt_first.
@@ -430,6 +431,7 @@ btendscan(PG_FUNCTION_ARGS)
                ReleaseBuffer(so->markPos.buf);
                so->markPos.buf = InvalidBuffer;
        }
+       so->markItemIndex = -1;
 
        if (so->killedItems != NULL)
                pfree(so->killedItems);
@@ -456,14 +458,16 @@ btmarkpos(PG_FUNCTION_ARGS)
                so->markPos.buf = InvalidBuffer;
        }
 
-       /* bump pin on current buffer for assignment to mark buffer */
+       /*
+        * Just record the current itemIndex.  If we later step to next page
+        * before releasing the marked position, _bt_steppage makes a full copy
+        * of the currPos struct in markPos.  If (as often happens) the mark is
+        * moved before we leave the page, we don't have to do that work.
+        */
        if (BTScanPosIsValid(so->currPos))
-       {
-               IncrBufferRefCount(so->currPos.buf);
-               memcpy(&so->markPos, &so->currPos,
-                          offsetof(BTScanPosData, items[1]) +
-                          so->currPos.lastItem * sizeof(BTScanPosItem));
-       }
+               so->markItemIndex = so->currPos.itemIndex;
+       else
+               so->markItemIndex = -1;
 
        PG_RETURN_VOID();
 }
@@ -477,24 +481,35 @@ btrestrpos(PG_FUNCTION_ARGS)
        IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
        BTScanOpaque so = (BTScanOpaque) scan->opaque;
 
-       /* we aren't holding any read locks, but gotta drop the pin */
-       if (BTScanPosIsValid(so->currPos))
+       if (so->markItemIndex >= 0)
        {
-               /* Before leaving current page, deal with any killed items */
-               if (so->numKilled > 0 &&
-                       so->currPos.buf != so->markPos.buf)
-                       _bt_killitems(scan, false);
-               ReleaseBuffer(so->currPos.buf);
-               so->currPos.buf = InvalidBuffer;
-       }
-
-       /* bump pin on marked buffer */
-       if (BTScanPosIsValid(so->markPos))
+               /*
+                * The mark position is on the same page we are currently on.
+                * Just restore the itemIndex.
+                */
+               so->currPos.itemIndex = so->markItemIndex;
+       } 
+       else
        {
-               IncrBufferRefCount(so->markPos.buf);
-               memcpy(&so->currPos, &so->markPos,
-                          offsetof(BTScanPosData, items[1]) +
-                          so->markPos.lastItem * sizeof(BTScanPosItem));
+               /* we aren't holding any read locks, but gotta drop the pin */
+               if (BTScanPosIsValid(so->currPos))
+               {
+                       /* Before leaving current page, deal with any killed items */
+                       if (so->numKilled > 0 &&
+                               so->currPos.buf != so->markPos.buf)
+                               _bt_killitems(scan, false);
+                       ReleaseBuffer(so->currPos.buf);
+                       so->currPos.buf = InvalidBuffer;
+               }
+
+               if (BTScanPosIsValid(so->markPos))
+               {
+                       /* bump pin on mark buffer for assignment to current buffer */
+                       IncrBufferRefCount(so->markPos.buf);
+                       memcpy(&so->currPos, &so->markPos,
+                                  offsetof(BTScanPosData, items[1]) +
+                                  so->markPos.lastItem * sizeof(BTScanPosItem));
+               }
        }
 
        PG_RETURN_VOID();
index 97a1ae466b0bb3b61455be3a190a041520d2ea31..84077baf188e147718040c88d6ace88ea10dea13 100644 (file)
@@ -815,6 +815,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
                so->currPos.moreRight = false;
        }
        so->numKilled = 0;                      /* just paranoia */
+       so->markItemIndex = -1;         /* ditto */
 
        /* position to the precise item on the page */
        offnum = _bt_binsrch(rel, buf, keysCount, scankeys, nextkey);
@@ -1053,6 +1054,21 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir)
        if (so->numKilled > 0)
                _bt_killitems(scan, true);
 
+       /*
+        * Before we modify currPos, make a copy of the page data if there
+        * was a mark position that needs it.
+        */
+       if (so->markItemIndex >= 0)
+       {
+               /* bump pin on current buffer for assignment to mark buffer */
+               IncrBufferRefCount(so->currPos.buf);
+               memcpy(&so->markPos, &so->currPos,
+                          offsetof(BTScanPosData, items[1]) +
+                          so->currPos.lastItem * sizeof(BTScanPosItem));
+               so->markPos.itemIndex = so->markItemIndex;
+               so->markItemIndex = -1;
+       }
+
        rel = scan->indexRelation;
 
        if (ScanDirectionIsForward(dir))
@@ -1408,6 +1424,7 @@ _bt_endpoint(IndexScanDesc scan, ScanDirection dir)
                so->currPos.moreRight = false;
        }
        so->numKilled = 0;                      /* just paranoia */
+       so->markItemIndex = -1;         /* ditto */
 
        /*
         * Now load data from the first page of the scan.
index 77a4ed130486fe265f017021159b35d74959bf5a..3c5c4cd2ef8360d88c6098f6281cec21be6ce2d0 100644 (file)
@@ -438,6 +438,15 @@ typedef struct BTScanOpaqueData
        int                *killedItems;        /* currPos.items indexes of killed items */
        int                     numKilled;              /* number of currently stored items */
 
+       /*
+        * If the marked position is on the same page as current position,
+        * we don't use markPos, but just keep the marked itemIndex in
+        * markItemIndex (all the rest of currPos is valid for the mark position).
+        * Hence, to determine if there is a mark, first look at markItemIndex,
+        * then at markPos.
+        */
+       int                     markItemIndex;  /* itemIndex, or -1 if not valid */
+
        /* keep these last in struct for efficiency */
        BTScanPosData currPos;          /* current position data */
        BTScanPosData markPos;          /* marked position, if any */