76
76
#include "optimizer/cost.h"
77
77
#include "optimizer/pathnode.h"
78
78
#include "optimizer/placeholder.h"
79
+ #include "optimizer/plancat.h"
79
80
#include "optimizer/planmain.h"
80
81
#include "optimizer/restrictinfo.h"
81
82
#include "parser/parsetree.h"
@@ -2986,7 +2987,7 @@ approx_tuple_count(PlannerInfo *root, JoinPath *path, List *quals)
2986
2987
* Set the size estimates for the given base relation.
2987
2988
*
2988
2989
* The rel's targetlist and restrictinfo list must have been constructed
2989
- * already.
2990
+ * already, and rel->tuples must be set .
2990
2991
*
2991
2992
* We set the following fields of the rel node:
2992
2993
* rows: the estimated number of output tuples (after applying
@@ -3151,6 +3152,76 @@ set_joinrel_size_estimates(PlannerInfo *root, RelOptInfo *rel,
3151
3152
rel -> rows = clamp_row_est (nrows );
3152
3153
}
3153
3154
3155
+ /*
3156
+ * set_subquery_size_estimates
3157
+ * Set the size estimates for a base relation that is a subquery.
3158
+ *
3159
+ * The rel's targetlist and restrictinfo list must have been constructed
3160
+ * already, and the plan for the subquery must have been completed.
3161
+ * We look at the subquery's plan and PlannerInfo to extract data.
3162
+ *
3163
+ * We set the same fields as set_baserel_size_estimates.
3164
+ */
3165
+ void
3166
+ set_subquery_size_estimates (PlannerInfo * root , RelOptInfo * rel ,
3167
+ PlannerInfo * subroot )
3168
+ {
3169
+ RangeTblEntry * rte ;
3170
+ ListCell * lc ;
3171
+
3172
+ /* Should only be applied to base relations that are subqueries */
3173
+ Assert (rel -> relid > 0 );
3174
+ rte = planner_rt_fetch (rel -> relid , root );
3175
+ Assert (rte -> rtekind == RTE_SUBQUERY );
3176
+
3177
+ /* Copy raw number of output rows from subplan */
3178
+ rel -> tuples = rel -> subplan -> plan_rows ;
3179
+
3180
+ /*
3181
+ * Compute per-output-column width estimates by examining the subquery's
3182
+ * targetlist. For any output that is a plain Var, get the width estimate
3183
+ * that was made while planning the subquery. Otherwise, fall back on a
3184
+ * datatype-based estimate.
3185
+ */
3186
+ foreach (lc , subroot -> parse -> targetList )
3187
+ {
3188
+ TargetEntry * te = (TargetEntry * ) lfirst (lc );
3189
+ Node * texpr = (Node * ) te -> expr ;
3190
+ int32 item_width ;
3191
+
3192
+ Assert (IsA (te , TargetEntry ));
3193
+ /* junk columns aren't visible to upper query */
3194
+ if (te -> resjunk )
3195
+ continue ;
3196
+
3197
+ /*
3198
+ * XXX This currently doesn't work for subqueries containing set
3199
+ * operations, because the Vars in their tlists are bogus references
3200
+ * to the first leaf subquery, which wouldn't give the right answer
3201
+ * even if we could still get to its PlannerInfo. So fall back on
3202
+ * datatype in that case.
3203
+ */
3204
+ if (IsA (texpr , Var ) &&
3205
+ subroot -> parse -> setOperations == NULL )
3206
+ {
3207
+ Var * var = (Var * ) texpr ;
3208
+ RelOptInfo * subrel = find_base_rel (subroot , var -> varno );
3209
+
3210
+ item_width = subrel -> attr_widths [var -> varattno - subrel -> min_attr ];
3211
+ }
3212
+ else
3213
+ {
3214
+ item_width = get_typavgwidth (exprType (texpr ), exprTypmod (texpr ));
3215
+ }
3216
+ Assert (item_width > 0 );
3217
+ Assert (te -> resno >= rel -> min_attr && te -> resno <= rel -> max_attr );
3218
+ rel -> attr_widths [te -> resno - rel -> min_attr ] = item_width ;
3219
+ }
3220
+
3221
+ /* Now estimate number of output rows, etc */
3222
+ set_baserel_size_estimates (root , rel );
3223
+ }
3224
+
3154
3225
/*
3155
3226
* set_function_size_estimates
3156
3227
* Set the size estimates for a base relation that is a function call.
@@ -3251,11 +3322,17 @@ set_cte_size_estimates(PlannerInfo *root, RelOptInfo *rel, Plan *cteplan)
3251
3322
* set_rel_width
3252
3323
* Set the estimated output width of a base relation.
3253
3324
*
3325
+ * The estimated output width is the sum of the per-attribute width estimates
3326
+ * for the actually-referenced columns, plus any PHVs or other expressions
3327
+ * that have to be calculated at this relation. This is the amount of data
3328
+ * we'd need to pass upwards in case of a sort, hash, etc.
3329
+ *
3254
3330
* NB: this works best on plain relations because it prefers to look at
3255
- * real Vars. It will fail to make use of pg_statistic info when applied
3256
- * to a subquery relation, even if the subquery outputs are simple vars
3257
- * that we could have gotten info for. Is it worth trying to be smarter
3258
- * about subqueries?
3331
+ * real Vars. For subqueries, set_subquery_size_estimates will already have
3332
+ * copied up whatever per-column estimates were made within the subquery,
3333
+ * and for other types of rels there isn't much we can do anyway. We fall
3334
+ * back on (fairly stupid) datatype-based width estimates if we can't get
3335
+ * any better number.
3259
3336
*
3260
3337
* The per-attribute width estimates are cached for possible re-use while
3261
3338
* building join relations.
@@ -3265,6 +3342,7 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel)
3265
3342
{
3266
3343
Oid reloid = planner_rt_fetch (rel -> relid , root )-> relid ;
3267
3344
int32 tuple_width = 0 ;
3345
+ bool have_wholerow_var = false;
3268
3346
ListCell * lc ;
3269
3347
3270
3348
foreach (lc , rel -> reltargetlist )
@@ -3284,8 +3362,18 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel)
3284
3362
ndx = var -> varattno - rel -> min_attr ;
3285
3363
3286
3364
/*
3287
- * The width probably hasn't been cached yet, but may as well
3288
- * check
3365
+ * If it's a whole-row Var, we'll deal with it below after we
3366
+ * have already cached as many attr widths as possible.
3367
+ */
3368
+ if (var -> varattno == 0 )
3369
+ {
3370
+ have_wholerow_var = true;
3371
+ continue ;
3372
+ }
3373
+
3374
+ /*
3375
+ * The width may have been cached already (especially if it's
3376
+ * a subquery), so don't duplicate effort.
3289
3377
*/
3290
3378
if (rel -> attr_widths [ndx ] > 0 )
3291
3379
{
@@ -3294,7 +3382,7 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel)
3294
3382
}
3295
3383
3296
3384
/* Try to get column width from statistics */
3297
- if (reloid != InvalidOid )
3385
+ if (reloid != InvalidOid && var -> varattno > 0 )
3298
3386
{
3299
3387
item_width = get_attavgwidth (reloid , var -> varattno );
3300
3388
if (item_width > 0 )
@@ -3335,6 +3423,39 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel)
3335
3423
tuple_width += item_width ;
3336
3424
}
3337
3425
}
3426
+
3427
+ /*
3428
+ * If we have a whole-row reference, estimate its width as the sum of
3429
+ * per-column widths plus sizeof(HeapTupleHeaderData).
3430
+ */
3431
+ if (have_wholerow_var )
3432
+ {
3433
+ int32 wholerow_width = sizeof (HeapTupleHeaderData );
3434
+
3435
+ if (reloid != InvalidOid )
3436
+ {
3437
+ /* Real relation, so estimate true tuple width */
3438
+ wholerow_width += get_relation_data_width (reloid ,
3439
+ rel -> attr_widths - rel -> min_attr );
3440
+ }
3441
+ else
3442
+ {
3443
+ /* Do what we can with info for a phony rel */
3444
+ AttrNumber i ;
3445
+
3446
+ for (i = 1 ; i <= rel -> max_attr ; i ++ )
3447
+ wholerow_width += rel -> attr_widths [i - rel -> min_attr ];
3448
+ }
3449
+
3450
+ rel -> attr_widths [0 - rel -> min_attr ] = wholerow_width ;
3451
+
3452
+ /*
3453
+ * Include the whole-row Var as part of the output tuple. Yes,
3454
+ * that really is what happens at runtime.
3455
+ */
3456
+ tuple_width += wholerow_width ;
3457
+ }
3458
+
3338
3459
Assert (tuple_width >= 0 );
3339
3460
rel -> width = tuple_width ;
3340
3461
}
0 commit comments