Optimize the case where a btree indexscan has current and mark positions

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
This commit is contained in:
Tom Lane 2006-08-24 01:18:34 +00:00
parent 7ad642d0b5
commit 08ae5edc5c
3 changed files with 67 additions and 26 deletions

View File

@ -12,7 +12,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.149 2006/05/10 23:18:39 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.150 2006/08/24 01:18:34 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -392,6 +392,7 @@ btrescan(PG_FUNCTION_ARGS)
ReleaseBuffer(so->markPos.buf); ReleaseBuffer(so->markPos.buf);
so->markPos.buf = InvalidBuffer; so->markPos.buf = InvalidBuffer;
} }
so->markItemIndex = -1;
/* /*
* Reset the scan keys. Note that keys ordering stuff moved to _bt_first. * 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); ReleaseBuffer(so->markPos.buf);
so->markPos.buf = InvalidBuffer; so->markPos.buf = InvalidBuffer;
} }
so->markItemIndex = -1;
if (so->killedItems != NULL) if (so->killedItems != NULL)
pfree(so->killedItems); pfree(so->killedItems);
@ -456,14 +458,16 @@ btmarkpos(PG_FUNCTION_ARGS)
so->markPos.buf = InvalidBuffer; 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)) if (BTScanPosIsValid(so->currPos))
{ so->markItemIndex = so->currPos.itemIndex;
IncrBufferRefCount(so->currPos.buf); else
memcpy(&so->markPos, &so->currPos, so->markItemIndex = -1;
offsetof(BTScanPosData, items[1]) +
so->currPos.lastItem * sizeof(BTScanPosItem));
}
PG_RETURN_VOID(); PG_RETURN_VOID();
} }
@ -477,24 +481,35 @@ btrestrpos(PG_FUNCTION_ARGS)
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
BTScanOpaque so = (BTScanOpaque) scan->opaque; BTScanOpaque so = (BTScanOpaque) scan->opaque;
/* we aren't holding any read locks, but gotta drop the pin */ if (so->markItemIndex >= 0)
if (BTScanPosIsValid(so->currPos))
{ {
/* Before leaving current page, deal with any killed items */ /*
if (so->numKilled > 0 && * The mark position is on the same page we are currently on.
so->currPos.buf != so->markPos.buf) * Just restore the itemIndex.
_bt_killitems(scan, false); */
ReleaseBuffer(so->currPos.buf); so->currPos.itemIndex = so->markItemIndex;
so->currPos.buf = InvalidBuffer; }
} else
{
/* 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;
}
/* bump pin on marked buffer */ if (BTScanPosIsValid(so->markPos))
if (BTScanPosIsValid(so->markPos)) {
{ /* bump pin on mark buffer for assignment to current buffer */
IncrBufferRefCount(so->markPos.buf); IncrBufferRefCount(so->markPos.buf);
memcpy(&so->currPos, &so->markPos, memcpy(&so->currPos, &so->markPos,
offsetof(BTScanPosData, items[1]) + offsetof(BTScanPosData, items[1]) +
so->markPos.lastItem * sizeof(BTScanPosItem)); so->markPos.lastItem * sizeof(BTScanPosItem));
}
} }
PG_RETURN_VOID(); PG_RETURN_VOID();

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.105 2006/05/07 01:21:30 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.106 2006/08/24 01:18:34 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -815,6 +815,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
so->currPos.moreRight = false; so->currPos.moreRight = false;
} }
so->numKilled = 0; /* just paranoia */ so->numKilled = 0; /* just paranoia */
so->markItemIndex = -1; /* ditto */
/* position to the precise item on the page */ /* position to the precise item on the page */
offnum = _bt_binsrch(rel, buf, keysCount, scankeys, nextkey); offnum = _bt_binsrch(rel, buf, keysCount, scankeys, nextkey);
@ -1053,6 +1054,21 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir)
if (so->numKilled > 0) if (so->numKilled > 0)
_bt_killitems(scan, true); _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; rel = scan->indexRelation;
if (ScanDirectionIsForward(dir)) if (ScanDirectionIsForward(dir))
@ -1408,6 +1424,7 @@ _bt_endpoint(IndexScanDesc scan, ScanDirection dir)
so->currPos.moreRight = false; so->currPos.moreRight = false;
} }
so->numKilled = 0; /* just paranoia */ so->numKilled = 0; /* just paranoia */
so->markItemIndex = -1; /* ditto */
/* /*
* Now load data from the first page of the scan. * Now load data from the first page of the scan.

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/access/nbtree.h,v 1.103 2006/08/07 16:57:57 tgl Exp $ * $PostgreSQL: pgsql/src/include/access/nbtree.h,v 1.104 2006/08/24 01:18:34 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -438,6 +438,15 @@ typedef struct BTScanOpaqueData
int *killedItems; /* currPos.items indexes of killed items */ int *killedItems; /* currPos.items indexes of killed items */
int numKilled; /* number of currently stored 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 */ /* keep these last in struct for efficiency */
BTScanPosData currPos; /* current position data */ BTScanPosData currPos; /* current position data */
BTScanPosData markPos; /* marked position, if any */ BTScanPosData markPos; /* marked position, if any */