Skip to content

Commit

Permalink
Fix handling of unavailable indexes in Scan hints
Browse files Browse the repository at this point in the history
As showed by the regression tests, this fixes a lot of correctness
issues behind the hints considered as "used" by the module but not
actually used because the index restrictions were applied before
enforcing a scan method.  For example, an index IndexScan with a list of
indexes not used caused two problems:
- The hint would be marked as used, but it resulted in being not used,
falling down to a sequential scan.
- Discarding all the indexes in the hint could cause invisible
regressions, as the hint would fail to consider any existing hints.

There was also an extra case with IndexScanRegexp where having a list of
indexes available turns out to cause a sequential scan and still mark
the hint as used.

This commit now prevents restrict_indexes from removing any indexes from
the relation index list if none of the hinted indexes are available, and
switches the scan enforcement method to be after the index restrictions
are applied.  This safeguard prevents an IndexScan hint supplied without
any available indexes to result in a sequential scan, for example.

Per discussion on #136.

Author: Sami Imseih
Backpatch-through: 13
  • Loading branch information
michaelpq committed Jul 11, 2023
1 parent 5921cd6 commit 684986a
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 107 deletions.
126 changes: 63 additions & 63 deletions expected/pg_hint_plan.out
Original file line number Diff line number Diff line change
Expand Up @@ -5545,15 +5545,15 @@ EXPLAIN (COSTS false) SELECT * FROM t5 WHERE t5.id = 1;
LOG: available indexes for IndexScan(t5):
LOG: pg_hint_plan:
used hint:
IndexScan(t5 no_exist)
not used hint:
IndexScan(t5 no_exist)
duplication hint:
error hint:

QUERY PLAN
--------------------
Seq Scan on t5
Filter: (id = 1)
QUERY PLAN
----------------------------------------------------------------------------------------
Index Scan using t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa on t5
Index Cond: (id = 1)
(2 rows)

/*+IndexScan(t5 t5_id1 t5_id2)*/
Expand Down Expand Up @@ -5593,15 +5593,15 @@ EXPLAIN (COSTS false) SELECT * FROM t5 WHERE t5.id = 1;
LOG: available indexes for IndexScan(t5):
LOG: pg_hint_plan:
used hint:
IndexScan(t5 no_exist5 no_exist2)
not used hint:
IndexScan(t5 no_exist5 no_exist2)
duplication hint:
error hint:

QUERY PLAN
--------------------
Seq Scan on t5
Filter: (id = 1)
QUERY PLAN
----------------------------------------------------------------------------------------
Index Scan using t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa on t5
Index Cond: (id = 1)
(2 rows)

-- outer inner
Expand Down Expand Up @@ -6720,8 +6720,8 @@ LOG: available indexes for IndexScan(p2_c3_c1):
LOG: available indexes for IndexScan(p2_c3_c2):
LOG: pg_hint_plan:
used hint:
IndexScan(p2 p2_val)
not used hint:
IndexScan(p2 p2_val)
duplication hint:
error hint:

Expand Down Expand Up @@ -6898,8 +6898,8 @@ LOG: available indexes for IndexScan(p2_c1_c1):
LOG: available indexes for IndexScan(p2_c1_c2):
LOG: pg_hint_plan:
used hint:
IndexScan(p2 no_exist)
not used hint:
IndexScan(p2 no_exist)
duplication hint:
error hint:

Expand Down Expand Up @@ -7261,47 +7261,47 @@ EXPLAIN (COSTS false) SELECT id FROM t5 WHERE id = 1;
LOG: available indexes for IndexScanRegexp(t5):
LOG: pg_hint_plan:
used hint:
IndexScanRegexp(t5 t5[^_].*)
not used hint:
IndexScanRegexp(t5 t5[^_].*)
duplication hint:
error hint:

QUERY PLAN
--------------------
Seq Scan on t5
Filter: (id = 1)
QUERY PLAN
---------------------------------------------------------------------------------------------
Index Only Scan using t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa on t5
Index Cond: (id = 1)
(2 rows)

/*+ IndexScanRegexp(t5 ^.*t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab)*/
EXPLAIN (COSTS false) SELECT id FROM t5 WHERE id = 1;
LOG: available indexes for IndexScanRegexp(t5):
LOG: pg_hint_plan:
used hint:
IndexScanRegexp(t5 ^.*t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab)
not used hint:
IndexScanRegexp(t5 ^.*t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab)
duplication hint:
error hint:

QUERY PLAN
--------------------
Seq Scan on t5
Filter: (id = 1)
QUERY PLAN
---------------------------------------------------------------------------------------------
Index Only Scan using t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa on t5
Index Cond: (id = 1)
(2 rows)

/*+ IndexScan(t5 t5_id[0-9].*)*/
EXPLAIN (COSTS false) SELECT id FROM t5 WHERE id = 1;
LOG: available indexes for IndexScan(t5):
LOG: pg_hint_plan:
used hint:
IndexScan(t5 t5_id[0-9].*)
not used hint:
IndexScan(t5 t5_id[0-9].*)
duplication hint:
error hint:

QUERY PLAN
--------------------
Seq Scan on t5
Filter: (id = 1)
QUERY PLAN
---------------------------------------------------------------------------------------------
Index Only Scan using t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa on t5
Index Cond: (id = 1)
(2 rows)

/*+ IndexOnlyScanRegexp(t5 t5_[^i].*)*/
Expand Down Expand Up @@ -7341,47 +7341,47 @@ EXPLAIN (COSTS false) SELECT id FROM t5 WHERE id = 1;
LOG: available indexes for IndexOnlyScanRegexp(t5):
LOG: pg_hint_plan:
used hint:
IndexOnlyScanRegexp(t5 t5[^_].*)
not used hint:
IndexOnlyScanRegexp(t5 t5[^_].*)
duplication hint:
error hint:

QUERY PLAN
--------------------
Seq Scan on t5
Filter: (id = 1)
QUERY PLAN
---------------------------------------------------------------------------------------------
Index Only Scan using t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa on t5
Index Cond: (id = 1)
(2 rows)

/*+ IndexOnlyScanRegexp(t5 ^.*t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab)*/
EXPLAIN (COSTS false) SELECT id FROM t5 WHERE id = 1;
LOG: available indexes for IndexOnlyScanRegexp(t5):
LOG: pg_hint_plan:
used hint:
IndexOnlyScanRegexp(t5 ^.*t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab)
not used hint:
IndexOnlyScanRegexp(t5 ^.*t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab)
duplication hint:
error hint:

QUERY PLAN
--------------------
Seq Scan on t5
Filter: (id = 1)
QUERY PLAN
---------------------------------------------------------------------------------------------
Index Only Scan using t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa on t5
Index Cond: (id = 1)
(2 rows)

/*+ IndexOnlyScan(t5 t5_id[0-9].*)*/
EXPLAIN (COSTS false) SELECT id FROM t5 WHERE id = 1;
LOG: available indexes for IndexOnlyScan(t5):
LOG: pg_hint_plan:
used hint:
IndexOnlyScan(t5 t5_id[0-9].*)
not used hint:
IndexOnlyScan(t5 t5_id[0-9].*)
duplication hint:
error hint:

QUERY PLAN
--------------------
Seq Scan on t5
Filter: (id = 1)
QUERY PLAN
---------------------------------------------------------------------------------------------
Index Only Scan using t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa on t5
Index Cond: (id = 1)
(2 rows)

/*+ BitmapScanRegexp(t5 t5_[^i].*)*/
Expand Down Expand Up @@ -7425,47 +7425,47 @@ EXPLAIN (COSTS false) SELECT id FROM t5 WHERE id = 1;
LOG: available indexes for BitmapScanRegexp(t5):
LOG: pg_hint_plan:
used hint:
BitmapScanRegexp(t5 t5[^_].*)
not used hint:
BitmapScanRegexp(t5 t5[^_].*)
duplication hint:
error hint:

QUERY PLAN
--------------------
Seq Scan on t5
Filter: (id = 1)
QUERY PLAN
---------------------------------------------------------------------------------------------
Index Only Scan using t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa on t5
Index Cond: (id = 1)
(2 rows)

/*+ BitmapScanRegexp(t5 ^.*t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab)*/
EXPLAIN (COSTS false) SELECT id FROM t5 WHERE id = 1;
LOG: available indexes for BitmapScanRegexp(t5):
LOG: pg_hint_plan:
used hint:
BitmapScanRegexp(t5 ^.*t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab)
not used hint:
BitmapScanRegexp(t5 ^.*t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab)
duplication hint:
error hint:

QUERY PLAN
--------------------
Seq Scan on t5
Filter: (id = 1)
QUERY PLAN
---------------------------------------------------------------------------------------------
Index Only Scan using t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa on t5
Index Cond: (id = 1)
(2 rows)

/*+ BitmapScan(t5 t5_id[0-9].*)*/
EXPLAIN (COSTS false) SELECT id FROM t5 WHERE id = 1;
LOG: available indexes for BitmapScan(t5):
LOG: pg_hint_plan:
used hint:
BitmapScan(t5 t5_id[0-9].*)
not used hint:
BitmapScan(t5 t5_id[0-9].*)
duplication hint:
error hint:

QUERY PLAN
--------------------
Seq Scan on t5
Filter: (id = 1)
QUERY PLAN
---------------------------------------------------------------------------------------------
Index Only Scan using t5_idaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa on t5
Index Cond: (id = 1)
(2 rows)

-- Inheritance
Expand Down Expand Up @@ -7588,8 +7588,8 @@ LOG: available indexes for IndexScanRegexp(p1_c3_c1):
LOG: available indexes for IndexScanRegexp(p1_c3_c2):
LOG: pg_hint_plan:
used hint:
IndexScanRegexp(p1 p1[^_].*)
not used hint:
IndexScanRegexp(p1 p1[^_].*)
duplication hint:
error hint:

Expand Down Expand Up @@ -7629,8 +7629,8 @@ LOG: available indexes for IndexScan(p1_c3_c1):
LOG: available indexes for IndexScan(p1_c3_c2):
LOG: pg_hint_plan:
used hint:
IndexScan(p1 p1_.*val2.*)
not used hint:
IndexScan(p1 p1_.*val2.*)
duplication hint:
error hint:

Expand Down Expand Up @@ -7752,8 +7752,8 @@ LOG: available indexes for IndexOnlyScanRegexp(p1_c3_c1):
LOG: available indexes for IndexOnlyScanRegexp(p1_c3_c2):
LOG: pg_hint_plan:
used hint:
IndexOnlyScanRegexp(p1 p1[^_].*)
not used hint:
IndexOnlyScanRegexp(p1 p1[^_].*)
duplication hint:
error hint:

Expand Down Expand Up @@ -7793,8 +7793,8 @@ LOG: available indexes for IndexOnlyScan(p1_c3_c1):
LOG: available indexes for IndexOnlyScan(p1_c3_c2):
LOG: pg_hint_plan:
used hint:
IndexOnlyScan(p1 p1_.*val2.*)
not used hint:
IndexOnlyScan(p1 p1_.*val2.*)
duplication hint:
error hint:

Expand Down Expand Up @@ -7934,8 +7934,8 @@ LOG: available indexes for BitmapScanRegexp(p1_c3_c1):
LOG: available indexes for BitmapScanRegexp(p1_c3_c2):
LOG: pg_hint_plan:
used hint:
BitmapScanRegexp(p1 p1[^_].*)
not used hint:
BitmapScanRegexp(p1 p1[^_].*)
duplication hint:
error hint:

Expand Down Expand Up @@ -7975,8 +7975,8 @@ LOG: available indexes for BitmapScan(p1_c3_c1):
LOG: available indexes for BitmapScan(p1_c3_c2):
LOG: pg_hint_plan:
used hint:
BitmapScan(p1 p1_.*val2.*)
not used hint:
BitmapScan(p1 p1_.*val2.*)
duplication hint:
error hint:

Expand Down
Loading

0 comments on commit 684986a

Please sign in to comment.