diff options
Diffstat (limited to 'src/backend/access/nbtree/nbtsearch.c')
-rw-r--r-- | src/backend/access/nbtree/nbtsearch.c | 70 |
1 files changed, 67 insertions, 3 deletions
diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c index 17ad89749d5..c47eaed0e98 100644 --- a/src/backend/access/nbtree/nbtsearch.c +++ b/src/backend/access/nbtree/nbtsearch.c @@ -1429,6 +1429,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) /* remember which buffer we have pinned, if any */ Assert(!BTScanPosIsValid(so->currPos)); so->currPos.buf = buf; + so->firstPage = true; /* * Now load data from the first page of the scan. @@ -1539,6 +1540,7 @@ _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum) int itemIndex; bool continuescan; int indnatts; + bool requiredMatchedByPrecheck; /* * We must have the buffer pinned and locked, but the usual macro can't be @@ -1592,6 +1594,46 @@ _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum) */ Assert(BTScanPosIsPinned(so->currPos)); + /* + * Prechecking the page with scan keys required for direction scan. We + * check these keys with the last item on the page (according to our scan + * direction). If these keys are matched, we can skip checking them with + * every item on the page. Scan keys for our scan direction would + * necessarily match the previous items. Scan keys required for opposite + * direction scan are already matched by the _bt_first() call. + * + * With the forward scan, we do this check for the last item on the page + * instead of the high key. It's relatively likely that the most + * significant column in the high key will be different from the + * corresponding value from the last item on the page. So checking with + * the last item on the page would give a more precise answer. + * + * We skip this for the first page in the scan to evade the possible + * slowdown of the point queries. + */ + if (!so->firstPage && minoff < maxoff) + { + ItemId iid; + IndexTuple itup; + + iid = PageGetItemId(page, ScanDirectionIsForward(dir) ? maxoff : minoff); + itup = (IndexTuple) PageGetItem(page, iid); + + /* + * Do the precheck. Note that we pass the pointer to + * 'requiredMatchedByPrecheck' to 'continuescan' argument. That will + * set flag to true if all required keys are satisfied and false + * otherwise. + */ + (void) _bt_checkkeys(scan, itup, indnatts, dir, + &requiredMatchedByPrecheck, false); + } + else + { + so->firstPage = false; + requiredMatchedByPrecheck = false; + } + if (ScanDirectionIsForward(dir)) { /* load items[] in ascending order */ @@ -1603,6 +1645,7 @@ _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum) { ItemId iid = PageGetItemId(page, offnum); IndexTuple itup; + bool passes_quals; /* * If the scan specifies not to return killed tuples, then we @@ -1616,7 +1659,18 @@ _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum) itup = (IndexTuple) PageGetItem(page, iid); - if (_bt_checkkeys(scan, itup, indnatts, dir, &continuescan)) + passes_quals = _bt_checkkeys(scan, itup, indnatts, dir, + &continuescan, requiredMatchedByPrecheck); + + /* + * If the result of prechecking required keys was true, then in + * assert-enabled builds we also recheck that _bt_checkkeys() + * result is is the same. + */ + Assert(!requiredMatchedByPrecheck || + passes_quals == _bt_checkkeys(scan, itup, indnatts, dir, + &continuescan, false)); + if (passes_quals) { /* tuple passes all scan key conditions */ if (!BTreeTupleIsPosting(itup)) @@ -1673,7 +1727,7 @@ _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum) int truncatt; truncatt = BTreeTupleGetNAtts(itup, scan->indexRelation); - _bt_checkkeys(scan, itup, truncatt, dir, &continuescan); + _bt_checkkeys(scan, itup, truncatt, dir, &continuescan, false); } if (!continuescan) @@ -1725,7 +1779,16 @@ _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum) itup = (IndexTuple) PageGetItem(page, iid); passes_quals = _bt_checkkeys(scan, itup, indnatts, dir, - &continuescan); + &continuescan, requiredMatchedByPrecheck); + + /* + * If the result of prechecking required keys was true, then in + * assert-enabled builds we also recheck that _bt_checkkeys() + * result is is the same. + */ + Assert(!requiredMatchedByPrecheck || + passes_quals == _bt_checkkeys(scan, itup, indnatts, dir, + &continuescan, false)); if (passes_quals && tuple_alive) { /* tuple passes all scan key conditions */ @@ -2443,6 +2506,7 @@ _bt_endpoint(IndexScanDesc scan, ScanDirection dir) /* remember which buffer we have pinned */ so->currPos.buf = buf; + so->firstPage = true; _bt_initialize_more_data(so, dir); |