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

Commitf58b230

Browse files
committed
Cache if PathTarget and RestrictInfos contain volatile functions
Here we aim to reduce duplicate work done by contain_volatile_functions()by caching whether PathTargets and RestrictInfos contain any volatilefunctions the first time contain_volatile_functions() is called for them.Any future calls for these nodes just use the cached value rather thangoing to the trouble of recursively checking the sub-node all over again.Thanks to Tom Lane for the idea.Any locations in the code which make changes to a PathTarget orRestrictInfo which could change the outcome of the volatility check mustchange the cached value back to VOLATILITY_UNKNOWN again.contain_volatile_functions() is the only code in charge of setting thecache value to either VOLATILITY_VOLATILE or VOLATILITY_NOVOLATILE.Some existing code does benefit from this additional caching, however,this change is mainly aimed at an upcoming patch that must check forvolatility during the join search. Repeated volatility checks in thatcase can become very expensive when the join search contains more than afew relations.Author: David RowleyDiscussion:https://postgr.es/m/3795226.1614059027@sss.pgh.pa.us
1 parentb64654d commitf58b230

File tree

8 files changed

+134
-20
lines changed

8 files changed

+134
-20
lines changed

‎src/backend/nodes/copyfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2309,6 +2309,7 @@ _copyRestrictInfo(const RestrictInfo *from)
23092309
COPY_SCALAR_FIELD(can_join);
23102310
COPY_SCALAR_FIELD(pseudoconstant);
23112311
COPY_SCALAR_FIELD(leakproof);
2312+
COPY_SCALAR_FIELD(has_volatile);
23122313
COPY_SCALAR_FIELD(security_level);
23132314
COPY_BITMAPSET_FIELD(clause_relids);
23142315
COPY_BITMAPSET_FIELD(required_relids);

‎src/backend/nodes/outfuncs.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2471,6 +2471,7 @@ _outPathTarget(StringInfo str, const PathTarget *node)
24712471
WRITE_FLOAT_FIELD(cost.startup,"%.2f");
24722472
WRITE_FLOAT_FIELD(cost.per_tuple,"%.2f");
24732473
WRITE_INT_FIELD(width);
2474+
WRITE_ENUM_FIELD(has_volatile_expr,VolatileFunctionStatus);
24742475
}
24752476

24762477
staticvoid
@@ -2495,6 +2496,7 @@ _outRestrictInfo(StringInfo str, const RestrictInfo *node)
24952496
WRITE_BOOL_FIELD(can_join);
24962497
WRITE_BOOL_FIELD(pseudoconstant);
24972498
WRITE_BOOL_FIELD(leakproof);
2499+
WRITE_ENUM_FIELD(has_volatile,VolatileFunctionStatus);
24982500
WRITE_UINT_FIELD(security_level);
24992501
WRITE_BITMAPSET_FIELD(clause_relids);
25002502
WRITE_BITMAPSET_FIELD(required_relids);

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

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,8 @@ static void check_output_expressions(Query *subquery,
134134
staticvoidcompare_tlist_datatypes(List*tlist,List*colTypes,
135135
pushdown_safety_info*safetyInfo);
136136
staticbooltargetIsInAllPartitionLists(TargetEntry*tle,Query*query);
137-
staticboolqual_is_pushdown_safe(Query*subquery,Indexrti,Node*qual,
137+
staticboolqual_is_pushdown_safe(Query*subquery,Indexrti,
138+
RestrictInfo*rinfo,
138139
pushdown_safety_info*safetyInfo);
139140
staticvoidsubquery_push_qual(Query*subquery,
140141
RangeTblEntry*rte,Indexrti,Node*qual);
@@ -2177,11 +2178,12 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
21772178
foreach(l,rel->baserestrictinfo)
21782179
{
21792180
RestrictInfo*rinfo= (RestrictInfo*)lfirst(l);
2180-
Node*clause= (Node*)rinfo->clause;
21812181

21822182
if (!rinfo->pseudoconstant&&
2183-
qual_is_pushdown_safe(subquery,rti,clause,&safetyInfo))
2183+
qual_is_pushdown_safe(subquery,rti,rinfo,&safetyInfo))
21842184
{
2185+
Node*clause= (Node*)rinfo->clause;
2186+
21852187
/* Push it down */
21862188
subquery_push_qual(subquery,rte,rti,clause);
21872189
}
@@ -3390,37 +3392,39 @@ targetIsInAllPartitionLists(TargetEntry *tle, Query *query)
33903392
}
33913393

33923394
/*
3393-
* qual_is_pushdown_safe - is a particularqual safe to push down?
3395+
* qual_is_pushdown_safe - is a particularrinfo safe to push down?
33943396
*
3395-
*qual is a restriction clause applying to the given subquery (whose RTE
3397+
*rinfo is a restriction clause applying to the given subquery (whose RTE
33963398
* has index rti in the parent query).
33973399
*
33983400
* Conditions checked here:
33993401
*
3400-
* 1. The qual must not contain any SubPlans (mainly because I'm not sure
3401-
* it will work correctly: SubLinks will already have been transformed into
3402-
* SubPlans in the qual, but not in the subquery). Note that SubLinks that
3403-
* transform to initplans are safe, and will be accepted here because what
3404-
* we'll see in the qual is just a Param referencing the initplan output.
3402+
* 1. rinfo's clause must not contain any SubPlans (mainly because it's
3403+
* unclear that it will work correctly: SubLinks will already have been
3404+
* transformed into SubPlans in the qual, but not in the subquery). Note that
3405+
* SubLinks that transform to initplans are safe, and will be accepted here
3406+
* because what we'll see in the qual is just a Param referencing the initplan
3407+
* output.
34053408
*
3406-
* 2. If unsafeVolatile is set,the qual must not contain any volatile
3409+
* 2. If unsafeVolatile is set,rinfo's clause must not contain any volatile
34073410
* functions.
34083411
*
3409-
* 3. If unsafeLeaky is set,the qual must not contain any leaky functions
3410-
* that are passed Var nodes, and therefore might reveal values from the
3411-
* subquery as side effects.
3412+
* 3. If unsafeLeaky is set,rinfo's clause must not contain any leaky
3413+
*functionsthat are passed Var nodes, and therefore might reveal values from
3414+
*thesubquery as side effects.
34123415
*
3413-
* 4.The qual must not refer to the whole-row output of the subquery
3416+
* 4.rinfo's clause must not refer to the whole-row output of the subquery
34143417
* (since there is no easy way to name that within the subquery itself).
34153418
*
3416-
* 5.The qual must not refer to any subquery output columns that were
3419+
* 5.rinfo's clause must not refer to any subquery output columns that were
34173420
* found to be unsafe to reference by subquery_is_pushdown_safe().
34183421
*/
34193422
staticbool
3420-
qual_is_pushdown_safe(Query*subquery,Indexrti,Node*qual,
3423+
qual_is_pushdown_safe(Query*subquery,Indexrti,RestrictInfo*rinfo,
34213424
pushdown_safety_info*safetyInfo)
34223425
{
34233426
boolsafe= true;
3427+
Node*qual= (Node*)rinfo->clause;
34243428
List*vars;
34253429
ListCell*vl;
34263430

@@ -3430,7 +3434,7 @@ qual_is_pushdown_safe(Query *subquery, Index rti, Node *qual,
34303434

34313435
/* Refuse volatile quals if we found they'd be unsafe (point 2) */
34323436
if (safetyInfo->unsafeVolatile&&
3433-
contain_volatile_functions(qual))
3437+
contain_volatile_functions((Node*)rinfo))
34343438
return false;
34353439

34363440
/* Refuse leaky quals if told to (point 3) */

‎src/backend/optimizer/plan/initsplan.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2657,7 +2657,7 @@ check_mergejoinable(RestrictInfo *restrictinfo)
26572657
leftarg=linitial(((OpExpr*)clause)->args);
26582658

26592659
if (op_mergejoinable(opno,exprType(leftarg))&&
2660-
!contain_volatile_functions((Node*)clause))
2660+
!contain_volatile_functions((Node*)restrictinfo))
26612661
restrictinfo->mergeopfamilies=get_mergejoin_opfamilies(opno);
26622662

26632663
/*
@@ -2694,6 +2694,6 @@ check_hashjoinable(RestrictInfo *restrictinfo)
26942694
leftarg=linitial(((OpExpr*)clause)->args);
26952695

26962696
if (op_hashjoinable(opno,exprType(leftarg))&&
2697-
!contain_volatile_functions((Node*)clause))
2697+
!contain_volatile_functions((Node*)restrictinfo))
26982698
restrictinfo->hashjoinoperator=opno;
26992699
}

‎src/backend/optimizer/util/clauses.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,16 @@ contain_mutable_functions_walker(Node *node, void *context)
432432
* subsequent planning need not consider volatility within those, since
433433
* the executor won't change its evaluation rules for a SubPlan based on
434434
* volatility.
435+
*
436+
* For some node types, for example, RestrictInfo and PathTarget, we cache
437+
* whether we found any volatile functions or not and reuse that value in any
438+
* future checks for that node. All of the logic for determining if the
439+
* cached value should be set to VOLATILITY_NOVOLATILE or VOLATILITY_VOLATILE
440+
* belongs in this function. Any code which makes changes to these nodes
441+
* which could change the outcome this function must set the cached value back
442+
* to VOLATILITY_UNKNOWN. That allows this function to redetermine the
443+
* correct value during the next call, should we need to redetermine if the
444+
* node contains any volatile functions again in the future.
435445
*/
436446
bool
437447
contain_volatile_functions(Node*clause)
@@ -461,6 +471,63 @@ contain_volatile_functions_walker(Node *node, void *context)
461471
return true;
462472
}
463473

474+
if (IsA(node,RestrictInfo))
475+
{
476+
RestrictInfo*rinfo= (RestrictInfo*)node;
477+
478+
/*
479+
* For RestrictInfo, check if we've checked the volatility of it
480+
* before. If so, we can just use the cached value and not bother
481+
* checking it again. Otherwise, check it and cache if whether we
482+
* found any volatile functions.
483+
*/
484+
if (rinfo->has_volatile==VOLATILITY_NOVOLATILE)
485+
return false;
486+
elseif (rinfo->has_volatile==VOLATILITY_VOLATILE)
487+
return true;
488+
else
489+
{
490+
boolhasvolatile;
491+
492+
hasvolatile=contain_volatile_functions_walker((Node*)rinfo->clause,
493+
context);
494+
if (hasvolatile)
495+
rinfo->has_volatile=VOLATILITY_VOLATILE;
496+
else
497+
rinfo->has_volatile=VOLATILITY_NOVOLATILE;
498+
499+
returnhasvolatile;
500+
}
501+
}
502+
503+
if (IsA(node,PathTarget))
504+
{
505+
PathTarget*target= (PathTarget*)node;
506+
507+
/*
508+
* We also do caching for PathTarget the same as we do above for
509+
* RestrictInfos.
510+
*/
511+
if (target->has_volatile_expr==VOLATILITY_NOVOLATILE)
512+
return false;
513+
elseif (target->has_volatile_expr==VOLATILITY_VOLATILE)
514+
return true;
515+
else
516+
{
517+
boolhasvolatile;
518+
519+
hasvolatile=contain_volatile_functions_walker((Node*)target->exprs,
520+
context);
521+
522+
if (hasvolatile)
523+
target->has_volatile_expr=VOLATILITY_VOLATILE;
524+
else
525+
target->has_volatile_expr=VOLATILITY_NOVOLATILE;
526+
527+
returnhasvolatile;
528+
}
529+
}
530+
464531
/*
465532
* See notes in contain_mutable_functions_walker about why we treat
466533
* MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while

‎src/backend/optimizer/util/restrictinfo.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,13 @@ make_restrictinfo_internal(PlannerInfo *root,
137137
else
138138
restrictinfo->leakproof= false;/* really, "don't know" */
139139

140+
/*
141+
* Mark volatility as unknown. The contain_volatile_functions function
142+
* will determine if there are any volatile functions when called for the
143+
* first time with this RestrictInfo.
144+
*/
145+
restrictinfo->has_volatile=VOLATILITY_UNKNOWN;
146+
140147
/*
141148
* If it's a binary opclause, set up left/right relids info. In any case
142149
* set up the total clause relids info.

‎src/backend/optimizer/util/tlist.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,13 @@ make_pathtarget_from_tlist(List *tlist)
623623
i++;
624624
}
625625

626+
/*
627+
* Mark volatility as unknown. The contain_volatile_functions function
628+
* will determine if there are any volatile functions when called for the
629+
* first time with this PathTarget.
630+
*/
631+
target->has_volatile_expr=VOLATILITY_UNKNOWN;
632+
626633
returntarget;
627634
}
628635

@@ -724,6 +731,16 @@ add_column_to_pathtarget(PathTarget *target, Expr *expr, Index sortgroupref)
724731
target->sortgrouprefs= (Index*)palloc0(nexprs*sizeof(Index));
725732
target->sortgrouprefs[nexprs-1]=sortgroupref;
726733
}
734+
735+
/*
736+
* Reset has_volatile_expr to UNKNOWN. We just leave it up to
737+
* contain_volatile_functions to set this properly again. Technically we
738+
* could save some effort here and just check the new Expr, but it seems
739+
* better to keep the logic for setting this flag in one location rather
740+
* than duplicating the logic here.
741+
*/
742+
if (target->has_volatile_expr==VOLATILITY_NOVOLATILE)
743+
target->has_volatile_expr=VOLATILITY_UNKNOWN;
727744
}
728745

729746
/*

‎src/include/nodes/pathnodes.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,6 +1055,17 @@ typedef struct PathKey
10551055
boolpk_nulls_first;/* do NULLs come before normal values? */
10561056
}PathKey;
10571057

1058+
/*
1059+
* VolatileFunctionStatus -- allows nodes to cache their
1060+
* contain_volatile_functions properties. VOLATILITY_UNKNOWN means not yet
1061+
* determined.
1062+
*/
1063+
typedefenumVolatileFunctionStatus
1064+
{
1065+
VOLATILITY_UNKNOWN=0,
1066+
VOLATILITY_VOLATILE,
1067+
VOLATILITY_NOVOLATILE
1068+
}VolatileFunctionStatus;
10581069

10591070
/*
10601071
* PathTarget
@@ -1086,6 +1097,8 @@ typedef struct PathTarget
10861097
Index*sortgrouprefs;/* corresponding sort/group refnos, or 0 */
10871098
QualCostcost;/* cost of evaluating the expressions */
10881099
intwidth;/* estimated avg width of result tuples */
1100+
VolatileFunctionStatushas_volatile_expr;/* indicates if exprs contain
1101+
* any volatile functions. */
10891102
}PathTarget;
10901103

10911104
/* Convenience macro to get a sort/group refno from a PathTarget */
@@ -2016,6 +2029,9 @@ typedef struct RestrictInfo
20162029

20172030
boolleakproof;/* true if known to contain no leaked Vars */
20182031

2032+
VolatileFunctionStatushas_volatile;/* to indicate if clause contains
2033+
* any volatile functions. */
2034+
20192035
Indexsecurity_level;/* see comment above */
20202036

20212037
/* The set of relids (varnos) actually referenced in the clause: */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp