mirror of
https://github.com/postgres/postgres.git
synced 2025-06-11 20:28:21 +03:00
postgres_fdw: Push down partition-wise aggregation.
Since commit7012b132d0
, postgres_fdw has been able to push down the toplevel aggregation operation to the remote server. Commite2f1eb0ee3
made it possible to break down the toplevel aggregation into one aggregate per partition. This commit lets postgres_fdw push down aggregation in that case just as it does at the top level. In order to make this work, this commit adds an additional argument to the GetForeignUpperPaths FDW API. A matching argument is added to the signature for create_upper_paths_hook. Third-party code using either of these will need to be updated. Also adjust create_foreignscan_plan() so that it picks up the correct set of relids in this case. Jeevan Chalke, reviewed by Ashutosh Bapat and by me and with some adjustments by me. The larger patch series of which this patch is a part was also reviewed and tested by Antonin Houska, Rajkumar Raghuwanshi, David Rowley, Dilip Kumar, Konstantin Knizhnik, Pascal Legrand, and Rafia Sabih. Discussion: http://postgr.es/m/CAM2+6=V64_xhstVHie0Rz=KPEQnLJMZt_e314P0jaT_oJ9MR8A@mail.gmail.com Discussion: http://postgr.es/m/CAM2+6=XPWujjmj5zUaBTGDoB38CemwcPmjkRy0qOcsQj_V+2sQ@mail.gmail.com
This commit is contained in:
@ -352,7 +352,8 @@ static bool postgresRecheckForeignScan(ForeignScanState *node,
|
||||
static void postgresGetForeignUpperPaths(PlannerInfo *root,
|
||||
UpperRelationKind stage,
|
||||
RelOptInfo *input_rel,
|
||||
RelOptInfo *output_rel);
|
||||
RelOptInfo *output_rel,
|
||||
void *extra);
|
||||
|
||||
/*
|
||||
* Helper functions
|
||||
@ -419,7 +420,8 @@ static void conversion_error_callback(void *arg);
|
||||
static bool foreign_join_ok(PlannerInfo *root, RelOptInfo *joinrel,
|
||||
JoinType jointype, RelOptInfo *outerrel, RelOptInfo *innerrel,
|
||||
JoinPathExtraData *extra);
|
||||
static bool foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel);
|
||||
static bool foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel,
|
||||
Node *havingQual);
|
||||
static List *get_useful_pathkeys_for_relation(PlannerInfo *root,
|
||||
RelOptInfo *rel);
|
||||
static List *get_useful_ecs_for_relation(PlannerInfo *root, RelOptInfo *rel);
|
||||
@ -427,7 +429,8 @@ static void add_paths_with_pathkeys_for_rel(PlannerInfo *root, RelOptInfo *rel,
|
||||
Path *epq_path);
|
||||
static void add_foreign_grouping_paths(PlannerInfo *root,
|
||||
RelOptInfo *input_rel,
|
||||
RelOptInfo *grouped_rel);
|
||||
RelOptInfo *grouped_rel,
|
||||
GroupPathExtraData *extra);
|
||||
static void apply_server_options(PgFdwRelationInfo *fpinfo);
|
||||
static void apply_table_options(PgFdwRelationInfo *fpinfo);
|
||||
static void merge_fdw_options(PgFdwRelationInfo *fpinfo,
|
||||
@ -2775,12 +2778,15 @@ estimate_path_cost_size(PlannerInfo *root,
|
||||
else if (IS_UPPER_REL(foreignrel))
|
||||
{
|
||||
PgFdwRelationInfo *ofpinfo;
|
||||
PathTarget *ptarget = root->upper_targets[UPPERREL_GROUP_AGG];
|
||||
PathTarget *ptarget = foreignrel->reltarget;
|
||||
AggClauseCosts aggcosts;
|
||||
double input_rows;
|
||||
int numGroupCols;
|
||||
double numGroups = 1;
|
||||
|
||||
/* Make sure the core code set the pathtarget. */
|
||||
Assert(ptarget != NULL);
|
||||
|
||||
/*
|
||||
* This cost model is mixture of costing done for sorted and
|
||||
* hashed aggregates in cost_agg(). We are not sure which
|
||||
@ -2805,6 +2811,12 @@ estimate_path_cost_size(PlannerInfo *root,
|
||||
{
|
||||
get_agg_clause_costs(root, (Node *) fpinfo->grouped_tlist,
|
||||
AGGSPLIT_SIMPLE, &aggcosts);
|
||||
|
||||
/*
|
||||
* The cost of aggregates in the HAVING qual will be the same
|
||||
* for each child as it is for the parent, so there's no need
|
||||
* to use a translated version of havingQual.
|
||||
*/
|
||||
get_agg_clause_costs(root, (Node *) root->parse->havingQual,
|
||||
AGGSPLIT_SIMPLE, &aggcosts);
|
||||
}
|
||||
@ -5017,11 +5029,12 @@ postgresGetForeignJoinPaths(PlannerInfo *root,
|
||||
* this function to PgFdwRelationInfo of the input relation.
|
||||
*/
|
||||
static bool
|
||||
foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel)
|
||||
foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel,
|
||||
Node *havingQual)
|
||||
{
|
||||
Query *query = root->parse;
|
||||
PathTarget *grouping_target = root->upper_targets[UPPERREL_GROUP_AGG];
|
||||
PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) grouped_rel->fdw_private;
|
||||
PathTarget *grouping_target = grouped_rel->reltarget;
|
||||
PgFdwRelationInfo *ofpinfo;
|
||||
List *aggvars;
|
||||
ListCell *lc;
|
||||
@ -5131,11 +5144,11 @@ foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel)
|
||||
* Classify the pushable and non-pushable HAVING clauses and save them in
|
||||
* remote_conds and local_conds of the grouped rel's fpinfo.
|
||||
*/
|
||||
if (root->hasHavingQual && query->havingQual)
|
||||
if (havingQual)
|
||||
{
|
||||
ListCell *lc;
|
||||
|
||||
foreach(lc, (List *) query->havingQual)
|
||||
foreach(lc, (List *) havingQual)
|
||||
{
|
||||
Expr *expr = (Expr *) lfirst(lc);
|
||||
RestrictInfo *rinfo;
|
||||
@ -5232,7 +5245,8 @@ foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel)
|
||||
*/
|
||||
static void
|
||||
postgresGetForeignUpperPaths(PlannerInfo *root, UpperRelationKind stage,
|
||||
RelOptInfo *input_rel, RelOptInfo *output_rel)
|
||||
RelOptInfo *input_rel, RelOptInfo *output_rel,
|
||||
void *extra)
|
||||
{
|
||||
PgFdwRelationInfo *fpinfo;
|
||||
|
||||
@ -5252,7 +5266,8 @@ postgresGetForeignUpperPaths(PlannerInfo *root, UpperRelationKind stage,
|
||||
fpinfo->pushdown_safe = false;
|
||||
output_rel->fdw_private = fpinfo;
|
||||
|
||||
add_foreign_grouping_paths(root, input_rel, output_rel);
|
||||
add_foreign_grouping_paths(root, input_rel, output_rel,
|
||||
(GroupPathExtraData *) extra);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -5264,13 +5279,13 @@ postgresGetForeignUpperPaths(PlannerInfo *root, UpperRelationKind stage,
|
||||
*/
|
||||
static void
|
||||
add_foreign_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel,
|
||||
RelOptInfo *grouped_rel)
|
||||
RelOptInfo *grouped_rel,
|
||||
GroupPathExtraData *extra)
|
||||
{
|
||||
Query *parse = root->parse;
|
||||
PgFdwRelationInfo *ifpinfo = input_rel->fdw_private;
|
||||
PgFdwRelationInfo *fpinfo = grouped_rel->fdw_private;
|
||||
ForeignPath *grouppath;
|
||||
PathTarget *grouping_target;
|
||||
double rows;
|
||||
int width;
|
||||
Cost startup_cost;
|
||||
@ -5281,7 +5296,8 @@ add_foreign_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel,
|
||||
!root->hasHavingQual)
|
||||
return;
|
||||
|
||||
grouping_target = root->upper_targets[UPPERREL_GROUP_AGG];
|
||||
Assert(extra->patype == PARTITIONWISE_AGGREGATE_NONE ||
|
||||
extra->patype == PARTITIONWISE_AGGREGATE_FULL);
|
||||
|
||||
/* save the input_rel as outerrel in fpinfo */
|
||||
fpinfo->outerrel = input_rel;
|
||||
@ -5295,8 +5311,13 @@ add_foreign_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel,
|
||||
fpinfo->user = ifpinfo->user;
|
||||
merge_fdw_options(fpinfo, ifpinfo, NULL);
|
||||
|
||||
/* Assess if it is safe to push down aggregation and grouping. */
|
||||
if (!foreign_grouping_ok(root, grouped_rel))
|
||||
/*
|
||||
* Assess if it is safe to push down aggregation and grouping.
|
||||
*
|
||||
* Use HAVING qual from extra. In case of child partition, it will have
|
||||
* translated Vars.
|
||||
*/
|
||||
if (!foreign_grouping_ok(root, grouped_rel, extra->havingQual))
|
||||
return;
|
||||
|
||||
/* Estimate the cost of push down */
|
||||
@ -5312,7 +5333,7 @@ add_foreign_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel,
|
||||
/* Create and add foreign path to the grouping relation. */
|
||||
grouppath = create_foreignscan_path(root,
|
||||
grouped_rel,
|
||||
grouping_target,
|
||||
grouped_rel->reltarget,
|
||||
rows,
|
||||
startup_cost,
|
||||
total_cost,
|
||||
|
Reference in New Issue
Block a user