Skip to content

Commit c6e4133

Browse files
committed
Postpone calculating total_table_pages until after pruning/exclusion.
The planner doesn't make any use of root->total_table_pages until it estimates costs of indexscans, so we don't need to compute it as early as that's currently done. By doing the calculation between set_base_rel_sizes and set_base_rel_pathlists, we can omit relations that get removed from the query by partition pruning or constraint exclusion, which seems like a more accurate basis for costing. (Historical note: I think at the time this code was written, there was not a separation between the "set sizes" and "set pathlists" steps, so that this approach would have been impossible at the time. But now that we have that separation, this is clearly the better way to do things.) David Rowley, reviewed by Edmund Horner Discussion: https://postgr.es/m/CAKJS1f-NG1mRM0VOtkAG7=ZLQWihoqees9R4ki3CKBB0-fRfCA@mail.gmail.com
1 parent 77366d9 commit c6e4133

File tree

4 files changed

+49
-39
lines changed

4 files changed

+49
-39
lines changed

src/backend/optimizer/path/allpaths.c

+43-2
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ make_one_rel(PlannerInfo *root, List *joinlist)
147147
{
148148
RelOptInfo *rel;
149149
Index rti;
150+
double total_pages;
150151

151152
/*
152153
* Construct the all_baserels Relids set.
@@ -173,10 +174,45 @@ make_one_rel(PlannerInfo *root, List *joinlist)
173174
set_base_rel_consider_startup(root);
174175

175176
/*
176-
* Compute size estimates and consider_parallel flags for each base rel,
177-
* then generate access paths.
177+
* Compute size estimates and consider_parallel flags for each base rel.
178178
*/
179179
set_base_rel_sizes(root);
180+
181+
/*
182+
* We should now have size estimates for every actual table involved in
183+
* the query, and we also know which if any have been deleted from the
184+
* query by join removal, pruned by partition pruning, or eliminated by
185+
* constraint exclusion. So we can now compute total_table_pages.
186+
*
187+
* Note that appendrels are not double-counted here, even though we don't
188+
* bother to distinguish RelOptInfos for appendrel parents, because the
189+
* parents will have pages = 0.
190+
*
191+
* XXX if a table is self-joined, we will count it once per appearance,
192+
* which perhaps is the wrong thing ... but that's not completely clear,
193+
* and detecting self-joins here is difficult, so ignore it for now.
194+
*/
195+
total_pages = 0;
196+
for (rti = 1; rti < root->simple_rel_array_size; rti++)
197+
{
198+
RelOptInfo *brel = root->simple_rel_array[rti];
199+
200+
if (brel == NULL)
201+
continue;
202+
203+
Assert(brel->relid == rti); /* sanity check on array */
204+
205+
if (IS_DUMMY_REL(brel))
206+
continue;
207+
208+
if (IS_SIMPLE_REL(brel))
209+
total_pages += (double) brel->pages;
210+
}
211+
root->total_table_pages = total_pages;
212+
213+
/*
214+
* Generate access paths for each base rel.
215+
*/
180216
set_base_rel_pathlists(root);
181217

182218
/*
@@ -1271,6 +1307,11 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
12711307
* because some places assume rel->tuples is valid for any baserel.
12721308
*/
12731309
rel->tuples = parent_rows;
1310+
1311+
/*
1312+
* Note that we leave rel->pages as zero; this is important to avoid
1313+
* double-counting the appendrel tree in total_table_pages.
1314+
*/
12741315
}
12751316
else
12761317
{

src/backend/optimizer/plan/planmain.c

-30
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,6 @@ query_planner(PlannerInfo *root, List *tlist,
5757
Query *parse = root->parse;
5858
List *joinlist;
5959
RelOptInfo *final_rel;
60-
Index rti;
61-
double total_pages;
6260

6361
/*
6462
* If the query has an empty join tree, then it's something easy like
@@ -231,34 +229,6 @@ query_planner(PlannerInfo *root, List *tlist,
231229
*/
232230
extract_restriction_or_clauses(root);
233231

234-
/*
235-
* We should now have size estimates for every actual table involved in
236-
* the query, and we also know which if any have been deleted from the
237-
* query by join removal; so we can compute total_table_pages.
238-
*
239-
* Note that appendrels are not double-counted here, even though we don't
240-
* bother to distinguish RelOptInfos for appendrel parents, because the
241-
* parents will still have size zero.
242-
*
243-
* XXX if a table is self-joined, we will count it once per appearance,
244-
* which perhaps is the wrong thing ... but that's not completely clear,
245-
* and detecting self-joins here is difficult, so ignore it for now.
246-
*/
247-
total_pages = 0;
248-
for (rti = 1; rti < root->simple_rel_array_size; rti++)
249-
{
250-
RelOptInfo *brel = root->simple_rel_array[rti];
251-
252-
if (brel == NULL)
253-
continue;
254-
255-
Assert(brel->relid == rti); /* sanity check on array */
256-
257-
if (IS_SIMPLE_REL(brel))
258-
total_pages += (double) brel->pages;
259-
}
260-
root->total_table_pages = total_pages;
261-
262232
/*
263233
* Ready to do the primary planning.
264234
*/

src/backend/optimizer/util/plancat.c

+2-3
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,8 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
138138

139139
/*
140140
* Estimate relation size --- unless it's an inheritance parent, in which
141-
* case the size will be computed later in set_append_rel_pathlist, and we
142-
* must leave it zero for now to avoid bollixing the total_table_pages
143-
* calculation.
141+
* case the size we want is not the rel's own size but the size of its
142+
* inheritance tree. That will be computed in set_append_rel_size().
144143
*/
145144
if (!inhparent)
146145
estimate_rel_size(relation, rel->attr_widths - rel->min_attr,

src/include/nodes/relation.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,8 @@ typedef struct PlannerInfo
310310

311311
MemoryContext planner_cxt; /* context holding PlannerInfo */
312312

313-
double total_table_pages; /* # of pages in all tables of query */
313+
double total_table_pages; /* # of pages in all non-dummy tables of
314+
* query */
314315

315316
double tuple_fraction; /* tuple_fraction passed to query_planner */
316317
double limit_tuples; /* limit_tuples passed to query_planner */
@@ -687,9 +688,8 @@ typedef struct RelOptInfo
687688
bool has_eclass_joins; /* T means joininfo is incomplete */
688689

689690
/* used by partitionwise joins: */
690-
bool consider_partitionwise_join; /* consider partitionwise
691-
* join paths? (if
692-
* partitioned rel) */
691+
bool consider_partitionwise_join; /* consider partitionwise join
692+
* paths? (if partitioned rel) */
693693
Relids top_parent_relids; /* Relids of topmost parents (if "other"
694694
* rel) */
695695

0 commit comments

Comments
 (0)