Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit1a8d5af

Browse files
committed
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 sameinformation as before, but in a more useful format: in particular, thereis now a clear connection between an indexclause (an original restrictionclause from WHERE or JOIN/ON) and the indexquals (directly usable indexconditions) 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 listis always directly usable as an index condition. This gets rid of repeatedre-determination of which side of the clause is the indexkey during costingand plan generation, as well as repeated lookups of the commutatoroperator. To minimize the added up-front cost, the typical case ofcommuting a plain OpExpr is handled by a new special-purpose functioncommute_restrictinfo(). For RowCompareExprs, generating the new clauseproperly 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 thepretty-klugy original implementation did.Tracking the connection between original and derived clauses lets usalso track explicitly whether the derived clauses are an exact or lossytranslation of the original. This provides a cheap solution to gettingrid of unnecessary rechecks of boolean index clauses, which previouslyseemed like it'd be more expensive than it was worth.Another pleasant (IMO) side-effect is that EXPLAIN now always showsindex clauses with the indexkey on the left; this seems less confusing.This commit leaves expand_indexqual_conditions() and some relatedfunctions in a slightly messy state. I didn't bother to change themany more than minimally necessary to work with the new data structure,because all that code is going to be refactored out of existence ina follow-on patch.Discussion:https://postgr.es/m/22182.1549124950@sss.pgh.pa.us
1 parent6401583 commit1a8d5af

File tree

22 files changed

+698
-622
lines changed

22 files changed

+698
-622
lines changed

‎src/backend/nodes/nodeFuncs.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2192,6 +2192,17 @@ expression_tree_walker(Node *node,
21922192
/* groupClauses are deemed uninteresting */
21932193
}
21942194
break;
2195+
caseT_IndexClause:
2196+
{
2197+
IndexClause*iclause= (IndexClause*)node;
2198+
2199+
if (walker(iclause->rinfo,context))
2200+
return true;
2201+
if (expression_tree_walker((Node*)iclause->indexquals,
2202+
walker,context))
2203+
return true;
2204+
}
2205+
break;
21952206
caseT_PlaceHolderVar:
21962207
returnwalker(((PlaceHolderVar*)node)->phexpr,context);
21972208
caseT_InferenceElem:
@@ -2999,6 +3010,17 @@ expression_tree_mutator(Node *node,
29993010
return (Node*)newnode;
30003011
}
30013012
break;
3013+
caseT_IndexClause:
3014+
{
3015+
IndexClause*iclause= (IndexClause*)node;
3016+
IndexClause*newnode;
3017+
3018+
FLATCOPY(newnode,iclause,IndexClause);
3019+
MUTATE(newnode->rinfo,iclause->rinfo,RestrictInfo*);
3020+
MUTATE(newnode->indexquals,iclause->indexquals,List*);
3021+
return (Node*)newnode;
3022+
}
3023+
break;
30023024
caseT_PlaceHolderVar:
30033025
{
30043026
PlaceHolderVar*phv= (PlaceHolderVar*)node;

‎src/backend/nodes/outfuncs.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1744,8 +1744,6 @@ _outIndexPath(StringInfo str, const IndexPath *node)
17441744

17451745
WRITE_NODE_FIELD(indexinfo);
17461746
WRITE_NODE_FIELD(indexclauses);
1747-
WRITE_NODE_FIELD(indexquals);
1748-
WRITE_NODE_FIELD(indexqualcols);
17491747
WRITE_NODE_FIELD(indexorderbys);
17501748
WRITE_NODE_FIELD(indexorderbycols);
17511749
WRITE_ENUM_FIELD(indexscandir,ScanDirection);
@@ -2447,6 +2445,18 @@ _outRestrictInfo(StringInfo str, const RestrictInfo *node)
24472445
WRITE_OID_FIELD(hashjoinoperator);
24482446
}
24492447

2448+
staticvoid
2449+
_outIndexClause(StringInfostr,constIndexClause*node)
2450+
{
2451+
WRITE_NODE_TYPE("INDEXCLAUSE");
2452+
2453+
WRITE_NODE_FIELD(rinfo);
2454+
WRITE_NODE_FIELD(indexquals);
2455+
WRITE_BOOL_FIELD(lossy);
2456+
WRITE_INT_FIELD(indexcol);
2457+
WRITE_NODE_FIELD(indexcols);
2458+
}
2459+
24502460
staticvoid
24512461
_outPlaceHolderVar(StringInfostr,constPlaceHolderVar*node)
24522462
{
@@ -4044,6 +4054,9 @@ outNode(StringInfo str, const void *obj)
40444054
caseT_RestrictInfo:
40454055
_outRestrictInfo(str,obj);
40464056
break;
4057+
caseT_IndexClause:
4058+
_outIndexClause(str,obj);
4059+
break;
40474060
caseT_PlaceHolderVar:
40484061
_outPlaceHolderVar(str,obj);
40494062
break;

‎src/backend/optimizer/path/costsize.c

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ typedef struct
145145
QualCosttotal;
146146
}cost_qual_eval_context;
147147

148-
staticList*extract_nonindex_conditions(List*qual_clauses,List*indexquals);
148+
staticList*extract_nonindex_conditions(List*qual_clauses,List*indexclauses);
149149
staticMergeScanSelCache*cached_scansel(PlannerInfo*root,
150150
RestrictInfo*rinfo,
151151
PathKey*pathkey);
@@ -517,18 +517,17 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count,
517517
{
518518
path->path.rows=path->path.param_info->ppi_rows;
519519
/* qpquals come from the rel's restriction clauses and ppi_clauses */
520-
qpquals=list_concat(
521-
extract_nonindex_conditions(path->indexinfo->indrestrictinfo,
522-
path->indexquals),
520+
qpquals=list_concat(extract_nonindex_conditions(path->indexinfo->indrestrictinfo,
521+
path->indexclauses),
523522
extract_nonindex_conditions(path->path.param_info->ppi_clauses,
524-
path->indexquals));
523+
path->indexclauses));
525524
}
526525
else
527526
{
528527
path->path.rows=baserel->rows;
529528
/* qpquals come from just the rel's restriction clauses */
530529
qpquals=extract_nonindex_conditions(path->indexinfo->indrestrictinfo,
531-
path->indexquals);
530+
path->indexclauses);
532531
}
533532

534533
if (!enable_indexscan)
@@ -753,20 +752,19 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count,
753752
*
754753
* Given a list of quals to be enforced in an indexscan, extract the ones that
755754
* will have to be applied as qpquals (ie, the index machinery won't handle
756-
* them). The actual rules for this appear in create_indexscan_plan() in
757-
* createplan.c, but the full rules are fairly expensive and we don't want to
758-
* go to that much effort for index paths that don't get selected for the
759-
* final plan. So we approximate it as quals that don't appear directly in
760-
* indexquals and also are not redundant children of the same EquivalenceClass
761-
* as some indexqual. This method neglects some infrequently-relevant
762-
* considerations, specifically clauses that needn't be checked because they
763-
* are implied by an indexqual. It does not seem worth the cycles to try to
764-
* factor that in at this stage, even though createplan.c will take pains to
765-
* remove such unnecessary clauses from the qpquals list if this path is
766-
* selected for use.
755+
* them). Here we detect only whether a qual clause is directly redundant
756+
* with some indexclause. If the index path is chosen for use, createplan.c
757+
* will try a bit harder to get rid of redundant qual conditions; specifically
758+
* it will see if quals can be proven to be implied by the indexquals. But
759+
* it does not seem worth the cycles to try to factor that in at this stage,
760+
* since we're only trying to estimate qual eval costs. Otherwise this must
761+
* match the logic in create_indexscan_plan().
762+
*
763+
* qual_clauses, and the result, are lists of RestrictInfos.
764+
* indexclauses is a list of IndexClauses.
767765
*/
768766
staticList*
769-
extract_nonindex_conditions(List*qual_clauses,List*indexquals)
767+
extract_nonindex_conditions(List*qual_clauses,List*indexclauses)
770768
{
771769
List*result=NIL;
772770
ListCell*lc;
@@ -777,10 +775,8 @@ extract_nonindex_conditions(List *qual_clauses, List *indexquals)
777775

778776
if (rinfo->pseudoconstant)
779777
continue;/* we may drop pseudoconstants here */
780-
if (list_member_ptr(indexquals,rinfo))
781-
continue;/* simple duplicate */
782-
if (is_redundant_derived_clause(rinfo,indexquals))
783-
continue;/* derived from same EquivalenceClass */
778+
if (is_redundant_with_indexclauses(rinfo,indexclauses))
779+
continue;/* dup or derived from same EquivalenceClass */
784780
/* ... skip the predicate proof attempt createplan.c will try ... */
785781
result=lappend(result,rinfo);
786782
}
@@ -4242,8 +4238,7 @@ has_indexed_join_quals(NestPath *joinpath)
42424238
innerpath->parent->relids,
42434239
joinrelids))
42444240
{
4245-
if (!(list_member_ptr(indexclauses,rinfo)||
4246-
is_redundant_derived_clause(rinfo,indexclauses)))
4241+
if (!is_redundant_with_indexclauses(rinfo,indexclauses))
42474242
return false;
42484243
found_one= true;
42494244
}

‎src/backend/optimizer/path/equivclass.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2511,3 +2511,40 @@ is_redundant_derived_clause(RestrictInfo *rinfo, List *clauselist)
25112511

25122512
return false;
25132513
}
2514+
2515+
/*
2516+
* is_redundant_with_indexclauses
2517+
*Test whether rinfo is redundant with any clause in the IndexClause
2518+
*list. Here, for convenience, we test both simple identity and
2519+
*whether it is derived from the same EC as any member of the list.
2520+
*/
2521+
bool
2522+
is_redundant_with_indexclauses(RestrictInfo*rinfo,List*indexclauses)
2523+
{
2524+
EquivalenceClass*parent_ec=rinfo->parent_ec;
2525+
ListCell*lc;
2526+
2527+
foreach(lc,indexclauses)
2528+
{
2529+
IndexClause*iclause=lfirst_node(IndexClause,lc);
2530+
RestrictInfo*otherrinfo=iclause->rinfo;
2531+
2532+
/* If indexclause is lossy, it won't enforce the condition exactly */
2533+
if (iclause->lossy)
2534+
continue;
2535+
2536+
/* Match if it's same clause (pointer equality should be enough) */
2537+
if (rinfo==otherrinfo)
2538+
return true;
2539+
/* Match if derived from same EC */
2540+
if (parent_ec&&otherrinfo->parent_ec==parent_ec)
2541+
return true;
2542+
2543+
/*
2544+
* No need to look at the derived clauses in iclause->indexquals; they
2545+
* couldn't match if the parent clause didn't.
2546+
*/
2547+
}
2548+
2549+
return false;
2550+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp