1
0
mirror of https://github.com/postgres/postgres.git synced 2025-12-10 14:22:35 +03:00

Avoid pointer chasing in _bt_readpage inner loop.

Make _bt_readpage pass down the current scan direction to various
utility functions within its pstate variable.  Also have _bt_readpage
work off of a local copy of scan->ignore_killed_tuples within its
per-tuple loop (rather than using scan->ignore_killed_tuples directly).

Testing has shown that this significantly benefits large range scans,
which are naturally able to take full advantage of the pstate.startikey
optimization added by commit 8a510275.  Running a pgbench script with a
"SELECT abalance FROM pgbench_accounts WHERE aid BETWEEN ..." query
shows an increase in transaction throughput of over 5%.  There also
appears to be a small performance benefit when running pgbench's
built-in select-only script.

Follow-up to commit 65d6acbc.

Author: Peter Geoghegan <pg@bowt.ie>
Reviewed-By: Victor Yegorov <vyegorov@gmail.com>
Discussion: https://postgr.es/m/CAH2-WzmwMwcwKFgaf+mYPwiz3iL4AqpXnwtW_O0vqpWPXRom9Q@mail.gmail.com
This commit is contained in:
Peter Geoghegan
2025-12-08 13:48:09 -05:00
parent d0d0ba6cf6
commit 83a26ba59b

View File

@@ -31,6 +31,7 @@
typedef struct BTReadPageState typedef struct BTReadPageState
{ {
/* Input parameters, set by _bt_readpage for _bt_checkkeys */ /* Input parameters, set by _bt_readpage for _bt_checkkeys */
ScanDirection dir; /* current scan direction */
OffsetNumber minoff; /* Lowest non-pivot tuple's offset */ OffsetNumber minoff; /* Lowest non-pivot tuple's offset */
OffsetNumber maxoff; /* Highest non-pivot tuple's offset */ OffsetNumber maxoff; /* Highest non-pivot tuple's offset */
IndexTuple finaltup; /* Needed by scans with array keys */ IndexTuple finaltup; /* Needed by scans with array keys */
@@ -140,7 +141,8 @@ _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum,
OffsetNumber minoff; OffsetNumber minoff;
OffsetNumber maxoff; OffsetNumber maxoff;
BTReadPageState pstate; BTReadPageState pstate;
bool arrayKeys; bool arrayKeys,
ignore_killed_tuples = scan->ignore_killed_tuples;
int itemIndex, int itemIndex,
indnatts; indnatts;
@@ -151,7 +153,7 @@ _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum,
so->currPos.prevPage = opaque->btpo_prev; so->currPos.prevPage = opaque->btpo_prev;
so->currPos.nextPage = opaque->btpo_next; so->currPos.nextPage = opaque->btpo_next;
/* delay setting so->currPos.lsn until _bt_drop_lock_and_maybe_pin */ /* delay setting so->currPos.lsn until _bt_drop_lock_and_maybe_pin */
so->currPos.dir = dir; pstate.dir = so->currPos.dir = dir;
so->currPos.nextTupleOffset = 0; so->currPos.nextTupleOffset = 0;
/* either moreRight or moreLeft should be set now (may be unset later) */ /* either moreRight or moreLeft should be set now (may be unset later) */
@@ -244,7 +246,7 @@ _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum,
* If the scan specifies not to return killed tuples, then we * If the scan specifies not to return killed tuples, then we
* treat a killed tuple as not passing the qual * treat a killed tuple as not passing the qual
*/ */
if (scan->ignore_killed_tuples && ItemIdIsDead(iid)) if (ignore_killed_tuples && ItemIdIsDead(iid))
{ {
offnum = OffsetNumberNext(offnum); offnum = OffsetNumberNext(offnum);
continue; continue;
@@ -402,7 +404,7 @@ _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum,
* uselessly advancing to the page to the left. This is similar * uselessly advancing to the page to the left. This is similar
* to the high key optimization used by forward scans. * to the high key optimization used by forward scans.
*/ */
if (scan->ignore_killed_tuples && ItemIdIsDead(iid)) if (ignore_killed_tuples && ItemIdIsDead(iid))
{ {
if (offnum > minoff) if (offnum > minoff)
{ {
@@ -1157,8 +1159,8 @@ _bt_checkkeys(IndexScanDesc scan, BTReadPageState *pstate, bool arrayKeys,
IndexTuple tuple, int tupnatts) IndexTuple tuple, int tupnatts)
{ {
TupleDesc tupdesc = RelationGetDescr(scan->indexRelation); TupleDesc tupdesc = RelationGetDescr(scan->indexRelation);
BTScanOpaque so = (BTScanOpaque) scan->opaque; BTScanOpaque so PG_USED_FOR_ASSERTS_ONLY = (BTScanOpaque) scan->opaque;
ScanDirection dir = so->currPos.dir; ScanDirection dir = pstate->dir;
int ikey = pstate->startikey; int ikey = pstate->startikey;
bool res; bool res;
@@ -2059,8 +2061,7 @@ static void
_bt_checkkeys_look_ahead(IndexScanDesc scan, BTReadPageState *pstate, _bt_checkkeys_look_ahead(IndexScanDesc scan, BTReadPageState *pstate,
int tupnatts, TupleDesc tupdesc) int tupnatts, TupleDesc tupdesc)
{ {
BTScanOpaque so = (BTScanOpaque) scan->opaque; ScanDirection dir = pstate->dir;
ScanDirection dir = so->currPos.dir;
OffsetNumber aheadoffnum; OffsetNumber aheadoffnum;
IndexTuple ahead; IndexTuple ahead;
@@ -2193,7 +2194,7 @@ _bt_advance_array_keys(IndexScanDesc scan, BTReadPageState *pstate,
{ {
BTScanOpaque so = (BTScanOpaque) scan->opaque; BTScanOpaque so = (BTScanOpaque) scan->opaque;
Relation rel = scan->indexRelation; Relation rel = scan->indexRelation;
ScanDirection dir = so->currPos.dir; ScanDirection dir = pstate ? pstate->dir : ForwardScanDirection;
int arrayidx = 0; int arrayidx = 0;
bool beyond_end_advance = false, bool beyond_end_advance = false,
skip_array_advanced = false, skip_array_advanced = false,