mirror of
https://github.com/postgres/postgres.git
synced 2025-10-27 00:12:01 +03:00
Refactor the representation of indexable clauses in IndexPaths.
In place of three separate but interrelated lists (indexclauses, indexquals, and indexqualcols), an IndexPath now has one list "indexclauses" of IndexClause nodes. This holds basically the same information as before, but in a more useful format: in particular, there is now a clear connection between an indexclause (an original restriction clause from WHERE or JOIN/ON) and the indexquals (directly usable index conditions) derived from it. We also change the ground rules a bit by mandating that clause commutation, if needed, be done up-front so that what is stored in the indexquals list is always directly usable as an index condition. This gets rid of repeated re-determination of which side of the clause is the indexkey during costing and plan generation, as well as repeated lookups of the commutator operator. To minimize the added up-front cost, the typical case of commuting a plain OpExpr is handled by a new special-purpose function commute_restrictinfo(). For RowCompareExprs, generating the new clause properly commuted to begin with is not really any more complex than before, it's just different --- and we can save doing that work twice, as the pretty-klugy original implementation did. Tracking the connection between original and derived clauses lets us also track explicitly whether the derived clauses are an exact or lossy translation of the original. This provides a cheap solution to getting rid of unnecessary rechecks of boolean index clauses, which previously seemed like it'd be more expensive than it was worth. Another pleasant (IMO) side-effect is that EXPLAIN now always shows index clauses with the indexkey on the left; this seems less confusing. This commit leaves expand_indexqual_conditions() and some related functions in a slightly messy state. I didn't bother to change them any more than minimally necessary to work with the new data structure, because all that code is going to be refactored out of existence in a follow-on patch. Discussion: https://postgr.es/m/22182.1549124950@sss.pgh.pa.us
This commit is contained in:
@@ -145,7 +145,7 @@ typedef struct
|
||||
QualCost total;
|
||||
} cost_qual_eval_context;
|
||||
|
||||
static List *extract_nonindex_conditions(List *qual_clauses, List *indexquals);
|
||||
static List *extract_nonindex_conditions(List *qual_clauses, List *indexclauses);
|
||||
static MergeScanSelCache *cached_scansel(PlannerInfo *root,
|
||||
RestrictInfo *rinfo,
|
||||
PathKey *pathkey);
|
||||
@@ -517,18 +517,17 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count,
|
||||
{
|
||||
path->path.rows = path->path.param_info->ppi_rows;
|
||||
/* qpquals come from the rel's restriction clauses and ppi_clauses */
|
||||
qpquals = list_concat(
|
||||
extract_nonindex_conditions(path->indexinfo->indrestrictinfo,
|
||||
path->indexquals),
|
||||
qpquals = list_concat(extract_nonindex_conditions(path->indexinfo->indrestrictinfo,
|
||||
path->indexclauses),
|
||||
extract_nonindex_conditions(path->path.param_info->ppi_clauses,
|
||||
path->indexquals));
|
||||
path->indexclauses));
|
||||
}
|
||||
else
|
||||
{
|
||||
path->path.rows = baserel->rows;
|
||||
/* qpquals come from just the rel's restriction clauses */
|
||||
qpquals = extract_nonindex_conditions(path->indexinfo->indrestrictinfo,
|
||||
path->indexquals);
|
||||
path->indexclauses);
|
||||
}
|
||||
|
||||
if (!enable_indexscan)
|
||||
@@ -753,20 +752,19 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count,
|
||||
*
|
||||
* Given a list of quals to be enforced in an indexscan, extract the ones that
|
||||
* will have to be applied as qpquals (ie, the index machinery won't handle
|
||||
* them). The actual rules for this appear in create_indexscan_plan() in
|
||||
* createplan.c, but the full rules are fairly expensive and we don't want to
|
||||
* go to that much effort for index paths that don't get selected for the
|
||||
* final plan. So we approximate it as quals that don't appear directly in
|
||||
* indexquals and also are not redundant children of the same EquivalenceClass
|
||||
* as some indexqual. This method neglects some infrequently-relevant
|
||||
* considerations, specifically clauses that needn't be checked because they
|
||||
* are implied by an indexqual. It does not seem worth the cycles to try to
|
||||
* factor that in at this stage, even though createplan.c will take pains to
|
||||
* remove such unnecessary clauses from the qpquals list if this path is
|
||||
* selected for use.
|
||||
* them). Here we detect only whether a qual clause is directly redundant
|
||||
* with some indexclause. If the index path is chosen for use, createplan.c
|
||||
* will try a bit harder to get rid of redundant qual conditions; specifically
|
||||
* it will see if quals can be proven to be implied by the indexquals. But
|
||||
* it does not seem worth the cycles to try to factor that in at this stage,
|
||||
* since we're only trying to estimate qual eval costs. Otherwise this must
|
||||
* match the logic in create_indexscan_plan().
|
||||
*
|
||||
* qual_clauses, and the result, are lists of RestrictInfos.
|
||||
* indexclauses is a list of IndexClauses.
|
||||
*/
|
||||
static List *
|
||||
extract_nonindex_conditions(List *qual_clauses, List *indexquals)
|
||||
extract_nonindex_conditions(List *qual_clauses, List *indexclauses)
|
||||
{
|
||||
List *result = NIL;
|
||||
ListCell *lc;
|
||||
@@ -777,10 +775,8 @@ extract_nonindex_conditions(List *qual_clauses, List *indexquals)
|
||||
|
||||
if (rinfo->pseudoconstant)
|
||||
continue; /* we may drop pseudoconstants here */
|
||||
if (list_member_ptr(indexquals, rinfo))
|
||||
continue; /* simple duplicate */
|
||||
if (is_redundant_derived_clause(rinfo, indexquals))
|
||||
continue; /* derived from same EquivalenceClass */
|
||||
if (is_redundant_with_indexclauses(rinfo, indexclauses))
|
||||
continue; /* dup or derived from same EquivalenceClass */
|
||||
/* ... skip the predicate proof attempt createplan.c will try ... */
|
||||
result = lappend(result, rinfo);
|
||||
}
|
||||
@@ -4242,8 +4238,7 @@ has_indexed_join_quals(NestPath *joinpath)
|
||||
innerpath->parent->relids,
|
||||
joinrelids))
|
||||
{
|
||||
if (!(list_member_ptr(indexclauses, rinfo) ||
|
||||
is_redundant_derived_clause(rinfo, indexclauses)))
|
||||
if (!is_redundant_with_indexclauses(rinfo, indexclauses))
|
||||
return false;
|
||||
found_one = true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user