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

Commitcffd89c

Browse files
committed
Revise the planner's handling of "pseudoconstant" WHERE clauses, that is
clauses containing no variables and no volatile functions. Such a clausecan be used as a one-time qual in a gating Result plan node, to suppressplan execution entirely when it is false. Even when the clause is true,putting it in a gating node wins by avoiding repeated evaluation of theclause. In previous PG releases, query_planner() would do this forpseudoconstant clauses appearing at the top level of the jointree, butthere was no ability to generate a gating Result deeper in the plan tree.To fix it, get rid of the special case in query_planner(), and insteadprocess pseudoconstant clauses through the normal RestrictInfo qualdistribution mechanism. When a pseudoconstant clause is found attached toa path node in create_plan(), pull it out and generate a gating Result atthat point. This requires special-casing pseudoconstants in selectivityestimation and cost_qual_eval, but on the whole it's pretty clean.It probably even makes the planner a bit faster than before for the normalcase of no pseudoconstants, since removing pull_constant_clauses saves oneuseless traversal of the qual tree. Per gripe from Phil Frost.
1 parent68628fc commitcffd89c

File tree

20 files changed

+465
-295
lines changed

20 files changed

+465
-295
lines changed

‎src/backend/nodes/copyfuncs.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* Portions Copyright (c) 1994, Regents of the University of California
1616
*
1717
* IDENTIFICATION
18-
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.337 2006/06/27 03:43:19 momjian Exp $
18+
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.338 2006/07/01 18:38:32 tgl Exp $
1919
*
2020
*-------------------------------------------------------------------------
2121
*/
@@ -1264,6 +1264,7 @@ _copyRestrictInfo(RestrictInfo *from)
12641264
COPY_SCALAR_FIELD(is_pushed_down);
12651265
COPY_SCALAR_FIELD(outerjoin_delayed);
12661266
COPY_SCALAR_FIELD(can_join);
1267+
COPY_SCALAR_FIELD(pseudoconstant);
12671268
COPY_BITMAPSET_FIELD(clause_relids);
12681269
COPY_BITMAPSET_FIELD(required_relids);
12691270
COPY_BITMAPSET_FIELD(left_relids);

‎src/backend/nodes/outfuncs.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.274 2006/04/30 18:30:39 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.275 2006/07/01 18:38:32 tgl Exp $
1212
*
1313
* NOTES
1414
* Every node type that can appear in stored rules' parsetrees *must*
@@ -1107,8 +1107,7 @@ _outResultPath(StringInfo str, ResultPath *node)
11071107

11081108
_outPathInfo(str, (Path*)node);
11091109

1110-
WRITE_NODE_FIELD(subpath);
1111-
WRITE_NODE_FIELD(constantqual);
1110+
WRITE_NODE_FIELD(quals);
11121111
}
11131112

11141113
staticvoid
@@ -1185,6 +1184,7 @@ _outPlannerInfo(StringInfo str, PlannerInfo *node)
11851184
WRITE_BOOL_FIELD(hasJoinRTEs);
11861185
WRITE_BOOL_FIELD(hasOuterJoins);
11871186
WRITE_BOOL_FIELD(hasHavingQual);
1187+
WRITE_BOOL_FIELD(hasPseudoConstantQuals);
11881188
}
11891189

11901190
staticvoid
@@ -1252,6 +1252,7 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node)
12521252
WRITE_BOOL_FIELD(is_pushed_down);
12531253
WRITE_BOOL_FIELD(outerjoin_delayed);
12541254
WRITE_BOOL_FIELD(can_join);
1255+
WRITE_BOOL_FIELD(pseudoconstant);
12551256
WRITE_BITMAPSET_FIELD(clause_relids);
12561257
WRITE_BITMAPSET_FIELD(required_relids);
12571258
WRITE_BITMAPSET_FIELD(left_relids);

‎src/backend/optimizer/README

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ RelOptInfo - a relation or joined relations
329329
BitmapHeapPath - top of a bitmapped index scan
330330
TidPath - scan by CTID
331331
AppendPath - append multiple subpaths together
332-
ResultPath - a Result plan node (used forvariable-free tlist or qual)
332+
ResultPath - a Result plan node (used forFROM-less SELECT)
333333
MaterialPath - a Material plan node
334334
UniquePath - remove duplicate rows
335335
NestPath - nested-loop joins

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.146 2006/05/02 04:34:18 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.147 2006/07/01 18:38:32 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -446,7 +446,9 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
446446
* There are several cases where we cannot push down clauses. Restrictions
447447
* involving the subquery are checked by subquery_is_pushdown_safe().
448448
* Restrictions on individual clauses are checked by
449-
* qual_is_pushdown_safe().
449+
* qual_is_pushdown_safe(). Also, we don't want to push down
450+
* pseudoconstant clauses; better to have the gating node above the
451+
* subquery.
450452
*
451453
* Non-pushed-down clauses will get evaluated as qpquals of the
452454
* SubqueryScan node.
@@ -466,7 +468,8 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
466468
RestrictInfo*rinfo= (RestrictInfo*)lfirst(l);
467469
Node*clause= (Node*)rinfo->clause;
468470

469-
if (qual_is_pushdown_safe(subquery,rti,clause,differentTypes))
471+
if (!rinfo->pseudoconstant&&
472+
qual_is_pushdown_safe(subquery,rti,clause,differentTypes))
470473
{
471474
/* Push it down */
472475
subquery_push_qual(subquery,rte,rti,clause);
@@ -1066,7 +1069,6 @@ print_path(PlannerInfo *root, Path *path, int indent)
10661069
break;
10671070
caseT_ResultPath:
10681071
ptype="Result";
1069-
subpath= ((ResultPath*)path)->subpath;
10701072
break;
10711073
caseT_MaterialPath:
10721074
ptype="Material";

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

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.79 2006/03/07 01:00:15 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.80 2006/07/01 18:38:32 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -117,10 +117,18 @@ clauselist_selectivity(PlannerInfo *root,
117117

118118
/*
119119
* Check for being passed a RestrictInfo.
120+
*
121+
* If it's a pseudoconstant RestrictInfo, then s2 is either 1.0 or
122+
* 0.0; just use that rather than looking for range pairs.
120123
*/
121124
if (IsA(clause,RestrictInfo))
122125
{
123126
rinfo= (RestrictInfo*)clause;
127+
if (rinfo->pseudoconstant)
128+
{
129+
s1=s1*s2;
130+
continue;
131+
}
124132
clause= (Node*)rinfo->clause;
125133
}
126134
else
@@ -422,6 +430,20 @@ clause_selectivity(PlannerInfo *root,
422430
{
423431
rinfo= (RestrictInfo*)clause;
424432

433+
/*
434+
* If the clause is marked pseudoconstant, then it will be used as
435+
* a gating qual and should not affect selectivity estimates; hence
436+
* return 1.0. The only exception is that a constant FALSE may
437+
* be taken as having selectivity 0.0, since it will surely mean
438+
* no rows out of the plan. This case is simple enough that we
439+
* need not bother caching the result.
440+
*/
441+
if (rinfo->pseudoconstant)
442+
{
443+
if (!IsA(rinfo->clause,Const))
444+
returns1;
445+
}
446+
425447
/*
426448
* If possible, cache the result of the selectivity calculation for
427449
* the clause.We can cache if varRelid is zero or the clause
@@ -509,7 +531,10 @@ clause_selectivity(PlannerInfo *root,
509531
elseif (IsA(clause,Const))
510532
{
511533
/* bool constant is pretty easy... */
512-
s1= ((bool) ((Const*)clause)->constvalue) ?1.0 :0.0;
534+
Const*con= (Const*)clause;
535+
536+
s1=con->constisnull ?0.0 :
537+
DatumGetBool(con->constvalue) ?1.0 :0.0;
513538
}
514539
elseif (IsA(clause,Param))
515540
{
@@ -519,7 +544,10 @@ clause_selectivity(PlannerInfo *root,
519544
if (IsA(subst,Const))
520545
{
521546
/* bool constant is pretty easy... */
522-
s1= ((bool) ((Const*)subst)->constvalue) ?1.0 :0.0;
547+
Const*con= (Const*)subst;
548+
549+
s1=con->constisnull ?0.0 :
550+
DatumGetBool(con->constvalue) ?1.0 :0.0;
523551
}
524552
else
525553
{

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

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
* Portions Copyright (c) 1994, Regents of the University of California
5555
*
5656
* IDENTIFICATION
57-
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.158 2006/06/06 17:59:57 tgl Exp $
57+
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.159 2006/07/01 18:38:32 tgl Exp $
5858
*
5959
*-------------------------------------------------------------------------
6060
*/
@@ -1604,20 +1604,29 @@ cost_qual_eval(QualCost *cost, List *quals)
16041604
* routine's use, so that it's not necessary to evaluate the qual
16051605
* clause's cost more than once. If the clause's cost hasn't been
16061606
* computed yet, the field's startup value will contain -1.
1607+
*
1608+
* If the RestrictInfo is marked pseudoconstant, it will be tested
1609+
* only once, so treat its cost as all startup cost.
16071610
*/
16081611
if (qual&&IsA(qual,RestrictInfo))
16091612
{
1610-
RestrictInfo*restrictinfo= (RestrictInfo*)qual;
1613+
RestrictInfo*rinfo= (RestrictInfo*)qual;
16111614

1612-
if (restrictinfo->eval_cost.startup<0)
1615+
if (rinfo->eval_cost.startup<0)
16131616
{
1614-
restrictinfo->eval_cost.startup=0;
1615-
restrictinfo->eval_cost.per_tuple=0;
1616-
cost_qual_eval_walker((Node*)restrictinfo->clause,
1617-
&restrictinfo->eval_cost);
1617+
rinfo->eval_cost.startup=0;
1618+
rinfo->eval_cost.per_tuple=0;
1619+
cost_qual_eval_walker((Node*)rinfo->clause,
1620+
&rinfo->eval_cost);
1621+
if (rinfo->pseudoconstant)
1622+
{
1623+
/* count one execution during startup */
1624+
rinfo->eval_cost.startup+=rinfo->eval_cost.per_tuple;
1625+
rinfo->eval_cost.per_tuple=0;
1626+
}
16181627
}
1619-
cost->startup+=restrictinfo->eval_cost.startup;
1620-
cost->per_tuple+=restrictinfo->eval_cost.per_tuple;
1628+
cost->startup+=rinfo->eval_cost.startup;
1629+
cost->per_tuple+=rinfo->eval_cost.per_tuple;
16211630
}
16221631
else
16231632
{
@@ -1876,7 +1885,9 @@ set_joinrel_size_estimates(PlannerInfo *root, RelOptInfo *rel,
18761885
*
18771886
* If we are doing an outer join, take that into account: the output must
18781887
* be at least as large as the non-nullable input.(Is there any chance
1879-
* of being even smarter?)
1888+
* of being even smarter?) (XXX this is not really right, because it
1889+
* assumes all the restriction clauses are join clauses; we should figure
1890+
* pushed-down clauses separately.)
18801891
*
18811892
* For JOIN_IN and variants, the Cartesian product is figured with respect
18821893
* to a unique-ified input, and then we can clamp to the size of the other

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

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.208 2006/06/07 17:08:07 tgl Exp $
12+
* $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.209 2006/07/01 18:38:32 tgl Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -998,6 +998,15 @@ match_clause_to_indexcol(IndexOptInfo *index,
998998
Oidexpr_op;
999999
boolplain_op;
10001000

1001+
/*
1002+
* Never match pseudoconstants to indexes. (Normally this could not
1003+
* happen anyway, since a pseudoconstant clause couldn't contain a
1004+
* Var, but what if someone builds an expression index on a constant?
1005+
* It's not totally unreasonable to do so with a partial index, either.)
1006+
*/
1007+
if (rinfo->pseudoconstant)
1008+
return false;
1009+
10011010
/* First check for boolean-index cases. */
10021011
if (IsBooleanOpclass(opclass))
10031012
{
@@ -2212,6 +2221,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
22122221
make_restrictinfo(boolqual,
22132222
true,
22142223
false,
2224+
false,
22152225
NULL));
22162226
continue;
22172227
}
@@ -2577,7 +2587,7 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
25772587
matching_cols);
25782588
rc->rargs=list_truncate((List*)copyObject(clause->rargs),
25792589
matching_cols);
2580-
returnmake_restrictinfo((Expr*)rc, true, false,NULL);
2590+
returnmake_restrictinfo((Expr*)rc, true, false,false,NULL);
25812591
}
25822592
else
25832593
{
@@ -2586,7 +2596,7 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
25862596
opexpr=make_opclause(linitial_oid(new_ops),BOOLOID, false,
25872597
copyObject(linitial(clause->largs)),
25882598
copyObject(linitial(clause->rargs)));
2589-
returnmake_restrictinfo(opexpr, true, false,NULL);
2599+
returnmake_restrictinfo(opexpr, true, false,false,NULL);
25902600
}
25912601
}
25922602

@@ -2678,7 +2688,7 @@ prefix_quals(Node *leftop, Oid opclass,
26782688
elog(ERROR,"no = operator for opclass %u",opclass);
26792689
expr=make_opclause(oproid,BOOLOID, false,
26802690
(Expr*)leftop, (Expr*)prefix_const);
2681-
result=list_make1(make_restrictinfo(expr, true, false,NULL));
2691+
result=list_make1(make_restrictinfo(expr, true, false,false,NULL));
26822692
returnresult;
26832693
}
26842694

@@ -2693,7 +2703,7 @@ prefix_quals(Node *leftop, Oid opclass,
26932703
elog(ERROR,"no >= operator for opclass %u",opclass);
26942704
expr=make_opclause(oproid,BOOLOID, false,
26952705
(Expr*)leftop, (Expr*)prefix_const);
2696-
result=list_make1(make_restrictinfo(expr, true, false,NULL));
2706+
result=list_make1(make_restrictinfo(expr, true, false,false,NULL));
26972707

26982708
/*-------
26992709
* If we can create a string larger than the prefix, we can say
@@ -2709,7 +2719,8 @@ prefix_quals(Node *leftop, Oid opclass,
27092719
elog(ERROR,"no < operator for opclass %u",opclass);
27102720
expr=make_opclause(oproid,BOOLOID, false,
27112721
(Expr*)leftop, (Expr*)greaterstr);
2712-
result=lappend(result,make_restrictinfo(expr, true, false,NULL));
2722+
result=lappend(result,
2723+
make_restrictinfo(expr, true, false, false,NULL));
27132724
}
27142725

27152726
returnresult;
@@ -2772,7 +2783,7 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop)
27722783
(Expr*)leftop,
27732784
(Expr*)makeConst(datatype,-1,opr1right,
27742785
false, false));
2775-
result=list_make1(make_restrictinfo(expr, true, false,NULL));
2786+
result=list_make1(make_restrictinfo(expr, true, false,false,NULL));
27762787

27772788
/* create clause "key <= network_scan_last( rightop )" */
27782789

@@ -2787,7 +2798,8 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop)
27872798
(Expr*)leftop,
27882799
(Expr*)makeConst(datatype,-1,opr2right,
27892800
false, false));
2790-
result=lappend(result,make_restrictinfo(expr, true, false,NULL));
2801+
result=lappend(result,
2802+
make_restrictinfo(expr, true, false, false,NULL));
27912803

27922804
returnresult;
27932805
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp