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

Commit491c24f

Browse files
committed
Make entirely-dummy appendrels get marked as such in set_append_rel_size.
The planner generally expects that the estimated rowcount of any relationis at least one row, *unless* it has been proven empty by constraintexclusion or similar mechanisms, which is marked by installing a dummy pathas the rel's cheapest path (cf. IS_DUMMY_REL). When I split upallpaths.c's processing of base rels into separate set_base_rel_sizes andset_base_rel_pathlists steps, the intention was that dummy rels would getmarked as such during the "set size" step; this is what justifies an Assertin indxpath.c's get_loop_count that other relations should either be dummyor have positive rowcount. Unfortunately I didn't get that quite rightfor append relations: if all the child rels have been proven empty thenset_append_rel_size would come up with a rowcount of zero, which iscorrect, but it didn't then do set_dummy_rel_pathlist. (We would haveended up with the right state after set_append_rel_pathlist, but that'stoo late, if we generate indexpaths for some other rel first.)In addition to fixing the actual bug, I installed an Assert enforcing thisconvention in set_rel_size; that then allows simplification of a coupleof now-redundant tests for zero rowcount in set_append_rel_size.Also, to cover the possibility that third-party FDWs have been carelessabout not returning a zero rowcount estimate, apply clamp_row_est towhatever an FDW comes up with as the rows estimate.Per report from Andreas Seltenreich. Back-patch to 9.2. Earlier branchesdid not have the separation between set_base_rel_sizes andset_base_rel_pathlists steps, so there was no intermediate state where anappendrel would have had inconsistent rowcount and pathlist. It's possiblethat adding the Assert to set_rel_size would be a good idea in olderbranches too; but since they're not under development any more, it's likelynot worth the trouble.
1 parent41ed5bb commit491c24f

File tree

3 files changed

+93
-42
lines changed

3 files changed

+93
-42
lines changed

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

Lines changed: 62 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,11 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
343343
break;
344344
}
345345
}
346+
347+
/*
348+
* We insist that all non-dummy rels have a nonzero rowcount estimate.
349+
*/
350+
Assert(rel->rows>0||IS_DUMMY_REL(rel));
346351
}
347352

348353
/*
@@ -461,6 +466,9 @@ set_foreign_size(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
461466

462467
/* Let FDW adjust the size estimates, if it can */
463468
rel->fdwroutine->GetForeignRelSize(root,rel,rte->relid);
469+
470+
/* ... but do not let it set the rows estimate to zero */
471+
rel->rows=clamp_row_est(rel->rows);
464472
}
465473

466474
/*
@@ -493,6 +501,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
493501
Indexrti,RangeTblEntry*rte)
494502
{
495503
intparentRTindex=rti;
504+
boolhas_live_children;
496505
doubleparent_rows;
497506
doubleparent_size;
498507
double*parent_attrsizes;
@@ -513,6 +522,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
513522
* Note: if you consider changing this logic, beware that child rels could
514523
* have zero rows and/or width, if they were excluded by constraints.
515524
*/
525+
has_live_children= false;
516526
parent_rows=0;
517527
parent_size=0;
518528
nattrs=rel->max_attr-rel->min_attr+1;
@@ -640,70 +650,80 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
640650
if (IS_DUMMY_REL(childrel))
641651
continue;
642652

653+
/* We have at least one live child. */
654+
has_live_children= true;
655+
643656
/*
644657
* Accumulate size information from each live child.
645658
*/
646-
if (childrel->rows>0)
659+
Assert(childrel->rows>0);
660+
661+
parent_rows+=childrel->rows;
662+
parent_size+=childrel->width*childrel->rows;
663+
664+
/*
665+
* Accumulate per-column estimates too. We need not do anything for
666+
* PlaceHolderVars in the parent list. If child expression isn't a
667+
* Var, or we didn't record a width estimate for it, we have to fall
668+
* back on a datatype-based estimate.
669+
*
670+
* By construction, child's reltargetlist is 1-to-1 with parent's.
671+
*/
672+
forboth(parentvars,rel->reltargetlist,
673+
childvars,childrel->reltargetlist)
647674
{
648-
parent_rows+=childrel->rows;
649-
parent_size+=childrel->width*childrel->rows;
675+
Var*parentvar= (Var*)lfirst(parentvars);
676+
Node*childvar= (Node*)lfirst(childvars);
650677

651-
/*
652-
* Accumulate per-column estimates too. We need not do anything
653-
* for PlaceHolderVars in the parent list. If child expression
654-
* isn't a Var, or we didn't record a width estimate for it, we
655-
* have to fall back on a datatype-based estimate.
656-
*
657-
* By construction, child's reltargetlist is 1-to-1 with parent's.
658-
*/
659-
forboth(parentvars,rel->reltargetlist,
660-
childvars,childrel->reltargetlist)
678+
if (IsA(parentvar,Var))
661679
{
662-
Var*parentvar= (Var*)lfirst(parentvars);
663-
Node*childvar= (Node*)lfirst(childvars);
680+
intpndx=parentvar->varattno-rel->min_attr;
681+
int32child_width=0;
664682

665-
if (IsA(parentvar,Var))
683+
if (IsA(childvar,Var)&&
684+
((Var*)childvar)->varno==childrel->relid)
666685
{
667-
intpndx=parentvar->varattno-rel->min_attr;
668-
int32child_width=0;
686+
intcndx= ((Var*)childvar)->varattno-childrel->min_attr;
669687

670-
if (IsA(childvar,Var)&&
671-
((Var*)childvar)->varno==childrel->relid)
672-
{
673-
intcndx= ((Var*)childvar)->varattno-childrel->min_attr;
674-
675-
child_width=childrel->attr_widths[cndx];
676-
}
677-
if (child_width <=0)
678-
child_width=get_typavgwidth(exprType(childvar),
679-
exprTypmod(childvar));
680-
Assert(child_width>0);
681-
parent_attrsizes[pndx]+=child_width*childrel->rows;
688+
child_width=childrel->attr_widths[cndx];
682689
}
690+
if (child_width <=0)
691+
child_width=get_typavgwidth(exprType(childvar),
692+
exprTypmod(childvar));
693+
Assert(child_width>0);
694+
parent_attrsizes[pndx]+=child_width*childrel->rows;
683695
}
684696
}
685697
}
686698

687-
/*
688-
* Save the finished size estimates.
689-
*/
690-
rel->rows=parent_rows;
691-
if (parent_rows>0)
699+
if (has_live_children)
692700
{
701+
/*
702+
* Save the finished size estimates.
703+
*/
693704
inti;
694705

706+
Assert(parent_rows>0);
707+
rel->rows=parent_rows;
695708
rel->width=rint(parent_size /parent_rows);
696709
for (i=0;i<nattrs;i++)
697710
rel->attr_widths[i]=rint(parent_attrsizes[i] /parent_rows);
711+
712+
/*
713+
* Set "raw tuples" count equal to "rows" for the appendrel; needed
714+
* because some places assume rel->tuples is valid for any baserel.
715+
*/
716+
rel->tuples=parent_rows;
698717
}
699718
else
700-
rel->width=0;/* attr_widths should be zero already */
701-
702-
/*
703-
* Set "raw tuples" count equal to "rows" for the appendrel; needed
704-
* because some places assume rel->tuples is valid for any baserel.
705-
*/
706-
rel->tuples=parent_rows;
719+
{
720+
/*
721+
* All children were excluded by constraints, so mark the whole
722+
* appendrel dummy. We must do this in this phase so that the rel's
723+
* dummy-ness is visible when we generate paths for other rels.
724+
*/
725+
set_dummy_rel_pathlist(rel);
726+
}
707727

708728
pfree(parent_attrsizes);
709729
}

‎src/test/regress/expected/join.out

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2164,6 +2164,26 @@ select count(*) from tenk1 x where
21642164
(1 row)
21652165

21662166
rollback;
2167+
--
2168+
-- regression test: be sure we cope with proven-dummy append rels
2169+
--
2170+
explain (costs off)
2171+
select aa, bb, unique1, unique1
2172+
from tenk1 right join b on aa = unique1
2173+
where bb < bb and bb is null;
2174+
QUERY PLAN
2175+
--------------------------
2176+
Result
2177+
One-Time Filter: false
2178+
(2 rows)
2179+
2180+
select aa, bb, unique1, unique1
2181+
from tenk1 right join b on aa = unique1
2182+
where bb < bb and bb is null;
2183+
aa | bb | unique1 | unique1
2184+
----+----+---------+---------
2185+
(0 rows)
2186+
21672187
--
21682188
-- Clean up
21692189
--

‎src/test/regress/sql/join.sql

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,17 @@ select count(*) from tenk1 x where
353353
x.unique1in (selectaa.f1from int4_tbl aa,float8_tbl bbwhereaa.f1=bb.f1);
354354
rollback;
355355

356+
--
357+
-- regression test: be sure we cope with proven-dummy append rels
358+
--
359+
explain (costs off)
360+
select aa, bb, unique1, unique1
361+
from tenk1right join bon aa= unique1
362+
where bb< bband bb isnull;
363+
364+
select aa, bb, unique1, unique1
365+
from tenk1right join bon aa= unique1
366+
where bb< bband bb isnull;
356367

357368
--
358369
-- Clean up

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp