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

Commitd007a95

Browse files
committed
Simple constraint exclusion. For now, only child tables of inheritance
scans are candidates for exclusion; this should be fixed eventually.Simon Riggs, with some help from Tom Lane.
1 parent9af9d67 commitd007a95

File tree

14 files changed

+621
-105
lines changed

14 files changed

+621
-105
lines changed

‎doc/src/sgml/runtime.sgml

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.338 2005/07/1405:13:38 tgl Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.339 2005/07/23 21:05:45 tgl Exp $
33
-->
44

55
<chapter Id="runtime">
@@ -2278,6 +2278,56 @@ archive_command = 'copy "%p" /mnt/server/archivedir/"%f"' # Windows
22782278
</listitem>
22792279
</varlistentry>
22802280

2281+
<varlistentry id="guc-enable-constraint-exclusion" xreflabel="enable_constraint_exclusion">
2282+
<term><varname>enable_constraint_exclusion</varname> (<type>boolean</type>)</term>
2283+
<indexterm>
2284+
<primary>constraint exclusion</primary>
2285+
</indexterm>
2286+
<indexterm>
2287+
<primary><varname>enable_constraint_exclusion</> configuration parameter</primary>
2288+
</indexterm>
2289+
<listitem>
2290+
<para>
2291+
Enables or disables the query planner's use of table constraints.
2292+
The default is <literal>off</>.
2293+
</para>
2294+
2295+
<para>
2296+
When this parameter is <literal>on</>, the planner compares query
2297+
conditions to table CHECK constraints, and omits scanning tables
2298+
for which the conditions contradict the constraints. (Presently
2299+
this is done only for child tables of inheritance scans.) For
2300+
example:
2301+
2302+
<programlisting>
2303+
CREATE TABLE parent(key integer, ...);
2304+
CREATE TABLE child1000(check (key between 1000 and 1999)) INHERITS(parent);
2305+
CREATE TABLE child2000(check (key between 2000 and 2999)) INHERITS(parent);
2306+
...
2307+
SELECT * FROM parent WHERE key = 2400;
2308+
</programlisting>
2309+
2310+
With constraint exclusion enabled, this SELECT will not scan
2311+
<structname>child1000</> at all. This can improve performance when
2312+
inheritance is used to build partitioned tables.
2313+
</para>
2314+
2315+
<para>
2316+
Currently, <varname>enable_constraint_exclusion</> defaults to
2317+
<literal>off</>, because it creates a risk of wrong answers when
2318+
query plans are cached: if a table constraint is changed or dropped,
2319+
the previously generated plan may now be wrong, and there is no
2320+
built-in mechanism to force re-planning. (This deficiency will
2321+
probably be addressed in a future
2322+
<productname>PostgreSQL</productname> release.) Another reason
2323+
for keeping it off is that the constraint checks are relatively
2324+
expensive to make, and in many circumstances will yield no savings.
2325+
It is recommended to turn this on only if you are actually using
2326+
partitioned tables designed to take advantage of the feature.
2327+
</para>
2328+
</listitem>
2329+
</varlistentry>
2330+
22812331
<varlistentry id="guc-from-collapse-limit" xreflabel="from_collapse_limit">
22822332
<term><varname>from_collapse_limit</varname> (<type>integer</type>)</term>
22832333
<indexterm>

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

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.134 2005/06/10 03:32:21 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.135 2005/07/23 21:05:46 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
1515

1616
#include"postgres.h"
1717

18+
#include"nodes/makefuncs.h"
1819
#ifdefOPTIMIZER_DEBUG
1920
#include"nodes/print.h"
2021
#endif
@@ -25,6 +26,7 @@
2526
#include"optimizer/paths.h"
2627
#include"optimizer/plancat.h"
2728
#include"optimizer/planner.h"
29+
#include"optimizer/predtest.h"
2830
#include"optimizer/prep.h"
2931
#include"optimizer/var.h"
3032
#include"parser/parsetree.h"
@@ -34,6 +36,7 @@
3436

3537

3638
/* These parameters are set by GUC */
39+
boolenable_constraint_exclusion= false;
3740
boolenable_geqo= false;/* just in case GUC doesn't set it */
3841
intgeqo_threshold;
3942

@@ -311,7 +314,37 @@ set_inherited_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
311314
childOID);
312315

313316
/*
314-
* Now compute child access paths, and save the cheapest.
317+
* If we can prove we don't need to scan this child via constraint
318+
* exclusion, just ignore it. (We have to have converted the
319+
* baserestrictinfo Vars before we can make the test.)
320+
*/
321+
if (enable_constraint_exclusion)
322+
{
323+
List*constraint_pred;
324+
325+
constraint_pred=get_relation_constraints(childOID,childrel);
326+
/*
327+
* We do not currently enforce that CHECK constraints contain
328+
* only immutable functions, so it's necessary to check here.
329+
* We daren't draw conclusions from plan-time evaluation of
330+
* non-immutable functions.
331+
*/
332+
if (!contain_mutable_functions((Node*)constraint_pred))
333+
{
334+
/*
335+
* The constraints are effectively ANDed together, so we can
336+
* just try to refute the entire collection at once. This may
337+
* allow us to make proofs that would fail if we took them
338+
* individually.
339+
*/
340+
if (predicate_refuted_by(constraint_pred,
341+
childrel->baserestrictinfo))
342+
continue;
343+
}
344+
}
345+
346+
/*
347+
* Compute the child's access paths, and save the cheapest.
315348
*/
316349
set_plain_rel_pathlist(root,childrel,childrte);
317350

@@ -345,7 +378,8 @@ set_inherited_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
345378

346379
/*
347380
* Finally, build Append path and install it as the only access path
348-
* for the parent rel.
381+
* for the parent rel. (Note: this is correct even if we have zero
382+
* or one live subpath due to constraint exclusion.)
349383
*/
350384
add_path(rel, (Path*)create_append_path(rel,subpaths));
351385

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

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*
1111
*
1212
* IDENTIFICATION
13-
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.194 2005/07/15 22:02:51 tgl Exp $
13+
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.195 2005/07/23 21:05:46 tgl Exp $
1414
*
1515
*-------------------------------------------------------------------------
1616
*/
@@ -40,7 +40,7 @@ static List *build_relation_tlist(RelOptInfo *rel);
4040
staticbooluse_physical_tlist(RelOptInfo*rel);
4141
staticvoiddisuse_physical_tlist(Plan*plan,Path*path);
4242
staticJoin*create_join_plan(PlannerInfo*root,JoinPath*best_path);
43-
staticAppend*create_append_plan(PlannerInfo*root,AppendPath*best_path);
43+
staticPlan*create_append_plan(PlannerInfo*root,AppendPath*best_path);
4444
staticResult*create_result_plan(PlannerInfo*root,ResultPath*best_path);
4545
staticMaterial*create_material_plan(PlannerInfo*root,MaterialPath*best_path);
4646
staticPlan*create_unique_plan(PlannerInfo*root,UniquePath*best_path);
@@ -435,14 +435,33 @@ create_join_plan(PlannerInfo *root, JoinPath *best_path)
435435
*
436436
* Returns a Plan node.
437437
*/
438-
staticAppend*
438+
staticPlan*
439439
create_append_plan(PlannerInfo*root,AppendPath*best_path)
440440
{
441441
Append*plan;
442442
List*tlist=build_relation_tlist(best_path->path.parent);
443443
List*subplans=NIL;
444444
ListCell*subpaths;
445445

446+
/*
447+
* It is possible for the subplans list to contain only one entry,
448+
* or even no entries. Handle these cases specially.
449+
*
450+
* XXX ideally, if there's just one entry, we'd not bother to generate
451+
* an Append node but just return the single child. At the moment this
452+
* does not work because the varno of the child scan plan won't match
453+
* the parent-rel Vars it'll be asked to emit.
454+
*/
455+
if (best_path->subpaths==NIL)
456+
{
457+
/* Generate a Result plan with constant-FALSE gating qual */
458+
return (Plan*)make_result(tlist,
459+
(Node*)list_make1(makeBoolConst(false,
460+
false)),
461+
NULL);
462+
}
463+
464+
/* Normal case with multiple subpaths */
446465
foreach(subpaths,best_path->subpaths)
447466
{
448467
Path*subpath= (Path*)lfirst(subpaths);
@@ -452,7 +471,7 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path)
452471

453472
plan=make_append(subplans, false,tlist);
454473

455-
returnplan;
474+
return(Plan*)plan;
456475
}
457476

458477
/*

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.5 2005/06/05 22:32:56 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.6 2005/07/23 21:05:46 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -184,7 +184,6 @@ optimize_minmax_aggregates(PlannerInfo *root, List *tlist, Path *best_path)
184184
*/
185185
if (IsA(best_path,ResultPath))
186186
{
187-
Assert(((ResultPath*)best_path)->subpath!=NULL);
188187
constant_quals= ((ResultPath*)best_path)->constantqual;
189188
/* no need to do this more than once: */
190189
constant_quals=order_qual_clauses(root,constant_quals);

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

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.112 2005/06/13 23:14:48 tgl Exp $
12+
* $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.113 2005/07/23 21:05:47 tgl Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -25,6 +25,7 @@
2525
#include"nodes/makefuncs.h"
2626
#include"optimizer/clauses.h"
2727
#include"optimizer/plancat.h"
28+
#include"optimizer/prep.h"
2829
#include"optimizer/tlist.h"
2930
#include"parser/parsetree.h"
3031
#include"parser/parse_expr.h"
@@ -359,6 +360,85 @@ estimate_rel_size(Relation rel, int32 *attr_widths,
359360
}
360361
}
361362

363+
364+
/*
365+
* get_relation_constraints
366+
*
367+
* Retrieve the CHECK constraint expressions of the given relation.
368+
*
369+
* Returns a List (possibly empty) of constraint expressions. Each one
370+
* has been canonicalized, and its Vars are changed to have the varno
371+
* indicated by rel->relid. This allows the expressions to be easily
372+
* compared to expressions taken from WHERE.
373+
*
374+
* Note: at present this is invoked at most once per relation per planner
375+
* run, and in many cases it won't be invoked at all, so there seems no
376+
* point in caching the data in RelOptInfo.
377+
*/
378+
List*
379+
get_relation_constraints(OidrelationObjectId,RelOptInfo*rel)
380+
{
381+
List*result=NIL;
382+
Indexvarno=rel->relid;
383+
Relationrelation;
384+
TupleConstr*constr;
385+
386+
/*
387+
* We assume the relation has already been safely locked.
388+
*/
389+
relation=heap_open(relationObjectId,NoLock);
390+
391+
constr=relation->rd_att->constr;
392+
if (constr!=NULL)
393+
{
394+
intnum_check=constr->num_check;
395+
inti;
396+
397+
for (i=0;i<num_check;i++)
398+
{
399+
Node*cexpr;
400+
401+
cexpr=stringToNode(constr->check[i].ccbin);
402+
403+
/*
404+
* Run each expression through const-simplification and
405+
* canonicalization. This is not just an optimization, but is
406+
* necessary, because we will be comparing it to
407+
* similarly-processed qual clauses, and may fail to detect valid
408+
* matches without this. This must match the processing done to
409+
* qual clauses in preprocess_expression()! (We can skip the
410+
* stuff involving subqueries, however, since we don't allow any
411+
* in check constraints.)
412+
*/
413+
cexpr=eval_const_expressions(cexpr);
414+
415+
cexpr= (Node*)canonicalize_qual((Expr*)cexpr);
416+
417+
/*
418+
* Also mark any coercion format fields as "don't care", so that
419+
* we can match to both explicit and implicit coercions.
420+
*/
421+
set_coercionform_dontcare(cexpr);
422+
423+
/* Fix Vars to have the desired varno */
424+
if (varno!=1)
425+
ChangeVarNodes(cexpr,1,varno,0);
426+
427+
/*
428+
* Finally, convert to implicit-AND format (that is, a List)
429+
* and append the resulting item(s) to our output list.
430+
*/
431+
result=list_concat(result,
432+
make_ands_implicit((Expr*)cexpr));
433+
}
434+
}
435+
436+
heap_close(relation,NoLock);
437+
438+
returnresult;
439+
}
440+
441+
362442
/*
363443
* build_physical_tlist
364444
*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp