Skip to content

Commit f587749

Browse files
committed
Partial index-only scan patch
1 parent e70501d commit f587749

File tree

6 files changed

+46
-8
lines changed

6 files changed

+46
-8
lines changed

src/backend/optimizer/path/costsize.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
#include "optimizer/placeholder.h"
9090
#include "optimizer/plancat.h"
9191
#include "optimizer/planmain.h"
92+
#include "optimizer/predtest.h"
9293
#include "optimizer/restrictinfo.h"
9394
#include "parser/parsetree.h"
9495
#include "utils/lsyscache.h"
@@ -429,7 +430,7 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count)
429430
path->path.rows = path->path.param_info->ppi_rows;
430431
/* qpquals come from the rel's restriction clauses and ppi_clauses */
431432
qpquals = list_concat(
432-
extract_nonindex_conditions(baserel->baserestrictinfo,
433+
extract_nonindex_conditions(path->indexrinfos,
433434
path->indexquals),
434435
extract_nonindex_conditions(path->path.param_info->ppi_clauses,
435436
path->indexquals));
@@ -438,7 +439,7 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count)
438439
{
439440
path->path.rows = baserel->rows;
440441
/* qpquals come from just the rel's restriction clauses */
441-
qpquals = extract_nonindex_conditions(baserel->baserestrictinfo,
442+
qpquals = extract_nonindex_conditions(path->indexrinfos,
442443
path->indexquals);
443444
}
444445

@@ -639,6 +640,7 @@ extract_nonindex_conditions(List *qual_clauses, List *indexquals)
639640
continue; /* simple duplicate */
640641
if (is_redundant_derived_clause(rinfo, indexquals))
641642
continue; /* derived from same EquivalenceClass */
643+
642644
/* ... skip the predicate proof attempts createplan.c will try ... */
643645
result = lappend(result, rinfo);
644646
}

src/backend/optimizer/path/indxpath.c

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ typedef struct
5959
bool nonempty; /* True if lists are not all empty */
6060
/* Lists of RestrictInfos, one per index column */
6161
List *indexclauses[INDEX_MAX_KEYS];
62+
List *indexrinfos; /* clauses not implied by predicate */
6263
} IndexClauseSet;
6364

6465
/* Per-path data used within choose_bitmap_and() */
@@ -129,7 +130,7 @@ static PathClauseUsage *classify_index_clause_usage(Path *path,
129130
static Relids get_bitmap_tree_required_outer(Path *bitmapqual);
130131
static void find_indexpath_quals(Path *bitmapqual, List **quals, List **preds);
131132
static int find_list_position(Node *node, List **nodelist);
132-
static bool check_index_only(RelOptInfo *rel, IndexOptInfo *index);
133+
static bool check_index_only(RelOptInfo *rel, IndexOptInfo *index, List *clauses);
133134
static double get_loop_count(PlannerInfo *root, Index cur_relid, Relids outer_relids);
134135
static double adjust_rowcount_for_semijoins(PlannerInfo *root,
135136
Index cur_relid,
@@ -866,6 +867,7 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
866867
double loop_count;
867868
List *orderbyclauses;
868869
List *orderbyclausecols;
870+
List *restrictinfo;
869871
List *index_pathkeys;
870872
List *useful_pathkeys;
871873
bool found_lower_saop_clause;
@@ -1013,13 +1015,16 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
10131015
orderbyclausecols = NIL;
10141016
}
10151017

1018+
restrictinfo
1019+
= (index->indpred != NIL) ? clauses->indexrinfos : rel->baserestrictinfo;
1020+
10161021
/*
10171022
* 3. Check if an index-only scan is possible. If we're not building
10181023
* plain indexscans, this isn't relevant since bitmap scans don't support
10191024
* index data retrieval anyway.
10201025
*/
10211026
index_only_scan = (scantype != ST_BITMAPSCAN &&
1022-
check_index_only(rel, index));
1027+
check_index_only(rel, index, restrictinfo));
10231028

10241029
/*
10251030
* 4. Generate an indexscan path if there are relevant restriction clauses
@@ -1033,6 +1038,7 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
10331038
ipath = create_index_path(root, index,
10341039
index_clauses,
10351040
clause_columns,
1041+
restrictinfo,
10361042
orderbyclauses,
10371043
orderbyclausecols,
10381044
useful_pathkeys,
@@ -1059,6 +1065,7 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
10591065
ipath = create_index_path(root, index,
10601066
index_clauses,
10611067
clause_columns,
1068+
restrictinfo,
10621069
NIL,
10631070
NIL,
10641071
useful_pathkeys,
@@ -1782,7 +1789,7 @@ find_list_position(Node *node, List **nodelist)
17821789
* Determine whether an index-only scan is possible for this index.
17831790
*/
17841791
static bool
1785-
check_index_only(RelOptInfo *rel, IndexOptInfo *index)
1792+
check_index_only(RelOptInfo *rel, IndexOptInfo *index, List *clauses)
17861793
{
17871794
bool result;
17881795
Bitmapset *attrs_used = NULL;
@@ -1814,8 +1821,11 @@ check_index_only(RelOptInfo *rel, IndexOptInfo *index)
18141821
*/
18151822
pull_varattnos((Node *) rel->reltargetlist, rel->relid, &attrs_used);
18161823

1817-
/* Add all the attributes used by restriction clauses. */
1818-
foreach(lc, rel->baserestrictinfo)
1824+
/*
1825+
* Add all the attributes used by restriction clauses (only those not
1826+
* implied by the index predicate for partial indexes).
1827+
*/
1828+
foreach(lc, clauses)
18191829
{
18201830
RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
18211831

@@ -2120,6 +2130,14 @@ match_clauses_to_index(IndexOptInfo *index,
21202130
* If the clause is usable, add it to the appropriate list in *clauseset.
21212131
* *clauseset must be initialized to zeroes before first call.
21222132
*
2133+
* For partial indexes we ignore clauses that are implied by the index
2134+
* predicate - no need to to re-evaluate those, and the columns may not
2135+
* even be included in the index itself.
2136+
*
2137+
* We also build a list of clauses that are not implied by the index
2138+
* predicate so that we don't need calling predicate_implied_by again
2139+
* (e.g. in check_index_only).
2140+
*
21232141
* Note: in some circumstances we may find the same RestrictInfos coming from
21242142
* multiple places. Defend against redundant outputs by refusing to add a
21252143
* clause twice (pointer equality should be a good enough check for this).
@@ -2136,6 +2154,16 @@ match_clause_to_index(IndexOptInfo *index,
21362154
{
21372155
int indexcol;
21382156

2157+
if (index->indpred != NIL)
2158+
{
2159+
if (predicate_implied_by(list_make1(rinfo->clause),
2160+
index->indpred))
2161+
return;
2162+
2163+
/* track non-implied restriction clauses */
2164+
clauseset->indexrinfos = lappend(clauseset->indexrinfos, rinfo);
2165+
}
2166+
21392167
for (indexcol = 0; indexcol < index->ncolumns; indexcol++)
21402168
{
21412169
if (match_clause_to_indexcol(index,

src/backend/optimizer/plan/planner.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4714,7 +4714,7 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid)
47144714

47154715
/* Estimate the cost of index scan */
47164716
indexScanPath = create_index_path(root, indexInfo,
4717-
NIL, NIL, NIL, NIL, NIL,
4717+
NIL, NIL, NIL, NIL, NIL, NIL,
47184718
ForwardScanDirection, false,
47194719
NULL, 1.0);
47204720

src/backend/optimizer/util/pathnode.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,7 @@ create_index_path(PlannerInfo *root,
993993
IndexOptInfo *index,
994994
List *indexclauses,
995995
List *indexclausecols,
996+
List *indexrinfos,
996997
List *indexorderbys,
997998
List *indexorderbycols,
998999
List *pathkeys,
@@ -1024,6 +1025,7 @@ create_index_path(PlannerInfo *root,
10241025
pathnode->indexclauses = indexclauses;
10251026
pathnode->indexquals = indexquals;
10261027
pathnode->indexqualcols = indexqualcols;
1028+
pathnode->indexrinfos = indexrinfos;
10271029
pathnode->indexorderbys = indexorderbys;
10281030
pathnode->indexorderbycols = indexorderbycols;
10291031
pathnode->indexscandir = indexscandir;

src/include/nodes/relation.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,10 @@ typedef struct Path
805805
* index column, so 'indexqualcols' must form a nondecreasing sequence.
806806
* (The order of multiple quals for the same index column is unspecified.)
807807
*
808+
* 'indexrinfos' is a list of RestrictInfo nodes from the query's WHERE
809+
* or JOIN conditions, excluding those implied by the index predicate
810+
* (if the index is not partial, the list includes all restriction clauses).
811+
*
808812
* 'indexorderbys', if not NIL, is a list of ORDER BY expressions that have
809813
* been found to be usable as ordering operators for an amcanorderbyop index.
810814
* The list must match the path's pathkeys, ie, one expression per pathkey
@@ -839,6 +843,7 @@ typedef struct IndexPath
839843
List *indexclauses;
840844
List *indexquals;
841845
List *indexqualcols;
846+
List *indexrinfos;
842847
List *indexorderbys;
843848
List *indexorderbycols;
844849
ScanDirection indexscandir;

src/include/optimizer/pathnode.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ extern IndexPath *create_index_path(PlannerInfo *root,
4141
IndexOptInfo *index,
4242
List *indexclauses,
4343
List *indexclausecols,
44+
List *indexrinfos,
4445
List *indexorderbys,
4546
List *indexorderbycols,
4647
List *pathkeys,

0 commit comments

Comments
 (0)