(2014/02/18 12:37), Tom Lane wrote:
> Etsuro Fujita <fujita.ets...@lab.ntt.co.jp> writes:
>> (2014/02/18 12:03), Tom Lane wrote:
>>> The calling FDW is supposed to do that; note the header comment.
> 
>> However, ISTM postgresGetForeignPaths() doesn't work like
>> that.  It uses the same rowcount for all paths of a same parameterization?
> 
> That's what we want no?

Maybe I'm missing something.  But I don't think
postgresGetForeignPaths() marks the parameterized path with the correct
row estimate.  Also, that function doesn't seem to estimate the cost of
the parameterized path correctly.  Please find attached a patch.

> Anyway, the point of using ppi_rows would be to enforce that all the
> rowcount estimates for a given parameterized relation are the same.
> In the FDW case, all those estimates are the FDW's responsibility,
> and so making them consistent is also its responsibility IMO.
> 
> Another way of looking at this is that none of the pathnode creation
> routines in pathnode.c are responsible for setting rowcount estimates.
> That's done by whatever is setting the cost estimate; this must be so,
> else the cost estimate is surely bogus.  So any way you slice it, the
> FDW has to get it right.

Understood.  Thank you for the analysis.

Sorry for the delay.

Best regards,
Etsuro Fujita
*** a/contrib/postgres_fdw/postgres_fdw.c
--- b/contrib/postgres_fdw/postgres_fdw.c
***************
*** 295,300 **** static bool postgresAnalyzeForeignTable(Relation relation,
--- 295,301 ----
  static void estimate_path_cost_size(PlannerInfo *root,
                                                RelOptInfo *baserel,
                                                List *join_conds,
+                                               List *param_conds,
                                                double *p_rows, int *p_width,
                                                Cost *p_startup_cost, Cost 
*p_total_cost);
  static void get_remote_estimate(const char *sql,
***************
*** 493,499 **** postgresGetForeignRelSize(PlannerInfo *root,
                 * values in fpinfo so we don't need to do it again to generate 
the
                 * basic foreign path.
                 */
!               estimate_path_cost_size(root, baserel, NIL,
                                                                &fpinfo->rows, 
&fpinfo->width,
                                                                
&fpinfo->startup_cost, &fpinfo->total_cost);
  
--- 494,500 ----
                 * values in fpinfo so we don't need to do it again to generate 
the
                 * basic foreign path.
                 */
!         estimate_path_cost_size(root, baserel, NIL, NIL,
                                                                &fpinfo->rows, 
&fpinfo->width,
                                                                
&fpinfo->startup_cost, &fpinfo->total_cost);
  
***************
*** 523,529 **** postgresGetForeignRelSize(PlannerInfo *root,
                set_baserel_size_estimates(root, baserel);
  
                /* Fill in basically-bogus cost estimates for use later. */
!               estimate_path_cost_size(root, baserel, NIL,
                                                                &fpinfo->rows, 
&fpinfo->width,
                                                                
&fpinfo->startup_cost, &fpinfo->total_cost);
        }
--- 524,530 ----
                set_baserel_size_estimates(root, baserel);
  
                /* Fill in basically-bogus cost estimates for use later. */
!               estimate_path_cost_size(root, baserel, NIL, NIL,
                                                                &fpinfo->rows, 
&fpinfo->width,
                                                                
&fpinfo->startup_cost, &fpinfo->total_cost);
        }
***************
*** 541,547 **** postgresGetForeignPaths(PlannerInfo *root,
--- 542,550 ----
        PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) baserel->fdw_private;
        ForeignPath *path;
        List       *join_quals;
+       List       *param_quals;
        Relids          required_outer;
+       ParamPathInfo *param_info;
        double          rows;
        int                     width;
        Cost            startup_cost;
***************
*** 591,604 **** postgresGetForeignPaths(PlannerInfo *root,
                if (!is_foreign_expr(root, baserel, rinfo->clause))
                        continue;
  
-               /*
-                * OK, get a cost estimate from the remote, and make a path.
-                */
-               join_quals = list_make1(rinfo);
-               estimate_path_cost_size(root, baserel, join_quals,
-                                                               &rows, &width,
-                                                               &startup_cost, 
&total_cost);
- 
                /* Must calculate required outer rels for this path */
                required_outer = bms_union(rinfo->clause_relids,
                                                                   
baserel->lateral_relids);
--- 594,599 ----
***************
*** 608,613 **** postgresGetForeignPaths(PlannerInfo *root,
--- 603,622 ----
                if (bms_is_empty(required_outer))
                        required_outer = NULL;
  
+               /*
+                * OK, get a cost estimate from the remote, and make a path.
+                */
+               join_quals = list_make1(rinfo);
+               param_info = get_baserel_parampathinfo(root, baserel, 
required_outer);
+               param_quals = list_copy(param_info->ppi_clauses);
+               estimate_path_cost_size(root, baserel, join_quals, param_quals,
+                                                               &rows, &width,
+                                                               &startup_cost, 
&total_cost);
+ 
+               /* Mark the path with the correct row estimate */
+               if (param_info)
+                       rows = param_info->ppi_rows;
+ 
                path = create_foreignscan_path(root, baserel,
                                                                           rows,
                                                                           
startup_cost,
***************
*** 667,686 **** postgresGetForeignPaths(PlannerInfo *root,
                                if (!is_foreign_expr(root, baserel, 
rinfo->clause))
                                        continue;
  
                                /*
                                 * OK, get a cost estimate from the remote, and 
make a path.
                                 */
                                join_quals = list_make1(rinfo);
!                               estimate_path_cost_size(root, baserel, 
join_quals,
                                                                                
&rows, &width,
                                                                                
&startup_cost, &total_cost);
  
!                               /* Must calculate required outer rels for this 
path */
!                               required_outer = bms_union(rinfo->clause_relids,
!                                                                               
   baserel->lateral_relids);
!                               required_outer = bms_del_member(required_outer, 
baserel->relid);
!                               if (bms_is_empty(required_outer))
!                                       required_outer = NULL;
  
                                path = create_foreignscan_path(root, baserel,
                                                                                
           rows,
--- 676,702 ----
                                if (!is_foreign_expr(root, baserel, 
rinfo->clause))
                                        continue;
  
+                               /* Must calculate required outer rels for this 
path */
+                               required_outer = bms_union(rinfo->clause_relids,
+                                                                               
   baserel->lateral_relids);
+                               required_outer = bms_del_member(required_outer, 
baserel->relid);
+                               if (bms_is_empty(required_outer))
+                                       required_outer = NULL;
+ 
                                /*
                                 * OK, get a cost estimate from the remote, and 
make a path.
                                 */
                                join_quals = list_make1(rinfo);
!                               param_info = get_baserel_parampathinfo(root, 
baserel,
!                                                                               
                           required_outer);
!                               param_quals = 
list_copy(param_info->ppi_clauses);
!                               estimate_path_cost_size(root, baserel, 
join_quals, param_quals,
                                                                                
&rows, &width,
                                                                                
&startup_cost, &total_cost);
  
!                               /* Mark the path with the correct row estimate 
*/
!                               if (param_info)
!                                       rows = param_info->ppi_rows;
  
                                path = create_foreignscan_path(root, baserel,
                                                                                
           rows,
***************
*** 1662,1673 **** postgresExplainForeignModify(ModifyTableState *mtstate,
   *            Get cost and size estimates for a foreign scan
   *
   * We assume that all the baserestrictinfo clauses will be applied, plus
!  * any join clauses listed in join_conds.
   */
  static void
  estimate_path_cost_size(PlannerInfo *root,
                                                RelOptInfo *baserel,
                                                List *join_conds,
                                                double *p_rows, int *p_width,
                                                Cost *p_startup_cost, Cost 
*p_total_cost)
  {
--- 1678,1691 ----
   *            Get cost and size estimates for a foreign scan
   *
   * We assume that all the baserestrictinfo clauses will be applied, plus
!  * any join clauses listed in join_conds and all the extra join clauses
!  * appearing in param_conds.
   */
  static void
  estimate_path_cost_size(PlannerInfo *root,
                                                RelOptInfo *baserel,
                                                List *join_conds,
+                                               List *param_conds,
                                                double *p_rows, int *p_width,
                                                Cost *p_startup_cost, Cost 
*p_total_cost)
  {
***************
*** 1723,1728 **** estimate_path_cost_size(PlannerInfo *root,
--- 1741,1764 ----
                /* Add in the eval cost of the local_conds */
                startup_cost += fpinfo->local_conds_cost.startup;
                total_cost += fpinfo->local_conds_cost.per_tuple * 
retrieved_rows;
+ 
+               /* Add in the eval cost of extra join clauses in the 
param_conds */
+               if (param_conds)
+               {
+                       List       *extra_conds;
+                       QualCost        extra_conds_cost;
+ 
+                       /*
+                        * We approximate the list of all the extra join 
clauses as
+                        * param_conds minus join_conds.  (We assume that 
pointer
+                        * equality is enough to recognize duplicate 
RestrictInfos.)
+                        */
+                       extra_conds = list_difference_ptr(param_conds, 
join_conds);
+                       cost_qual_eval(&extra_conds_cost, extra_conds, root);
+ 
+                       startup_cost += extra_conds_cost.startup;
+                       total_cost += extra_conds_cost.per_tuple * 
retrieved_rows;
+               }
        }
        else
        {
***************
*** 1731,1736 **** estimate_path_cost_size(PlannerInfo *root,
--- 1767,1773 ----
                 * parameterized paths can be made).
                 */
                Assert(join_conds == NIL);
+               Assert(param_conds == NIL);
  
                /* Use rows/width estimates made by set_baserel_size_estimates. 
*/
                rows = baserel->rows;
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to