*** a/src/backend/access/nbtree/nbtsearch.c --- b/src/backend/access/nbtree/nbtsearch.c *************** *** 997,1002 **** _bt_first(IndexScanDesc scan, ScanDirection dir) --- 997,1017 ---- offnum = OffsetNumberPrev(offnum); /* + * By here means scan position has been decided based on the first key. + * So check if further tuple also expected to match as per direction. + * If so then we can set SK_BT_MATCHED flag for this key so that next check + * of this key can avoided. + */ + if ((startKeys[0]->sk_strategy == BTGreaterEqualStrategyNumber + || startKeys[0]->sk_strategy == BTGreaterStrategyNumber) + && ScanDirectionIsForward(dir)) + startKeys[0]->sk_flags |= SK_BT_MATCHED; + else if ((startKeys[0]->sk_strategy == BTLessEqualStrategyNumber + || startKeys[0]->sk_strategy == BTLessStrategyNumber) + && ScanDirectionIsBackward(dir)) + startKeys[0]->sk_flags |= SK_BT_MATCHED; + + /* * Now load data from the first page of the scan. */ if (!_bt_readpage(scan, dir, offnum)) *** a/src/backend/access/nbtree/nbtutils.c --- b/src/backend/access/nbtree/nbtutils.c *************** *** 1429,1434 **** _bt_checkkeys(IndexScanDesc scan, --- 1429,1443 ---- bool isNull; Datum test; + /* + * If tuple does not have NULL values and this key has already matched, + * then the current tuple is expected to match. So safely deformation of + * tuple and comparison of keys can be skiped. + */ + if (key->sk_flags & SK_BT_MATCHED && !IndexTupleHasNulls(tuple)) + continue; + + /* row-comparison keys need special processing */ if (key->sk_flags & SK_ROW_HEADER) { *** a/src/include/access/nbtree.h --- b/src/include/access/nbtree.h *************** *** 617,622 **** typedef BTScanOpaqueData *BTScanOpaque; --- 617,623 ---- */ #define SK_BT_REQFWD 0x00010000 /* required to continue forward scan */ #define SK_BT_REQBKWD 0x00020000 /* required to continue backward scan */ + #define SK_BT_MATCHED 0x00040000 /* required to skip further key match */ #define SK_BT_INDOPTION_SHIFT 24 /* must clear the above bits */ #define SK_BT_DESC (INDOPTION_DESC << SK_BT_INDOPTION_SHIFT) #define SK_BT_NULLS_FIRST (INDOPTION_NULLS_FIRST << SK_BT_INDOPTION_SHIFT)