From 90ea7dcca36bf5e0713b028b639846803ad38a5d Mon Sep 17 00:00:00 2001 From: Jeevan Chalke Date: Wed, 18 May 2022 14:19:22 +0530 Subject: [PATCH] Add enable_aggregate_pushdown option to control aggregate push-down. Considering the complexity of generating the aggregation pipeline, add an option to control the push-down to avoid any issues. This option can be set at the server level or the table level. If any of the tables involved in the join has this option set to false, then the join will not be pushed down. The table-level value of the option takes precedence over the server-level option value. Default is true. FDW-137, Vaibhav Dalvi, reviewed by Suraj Kharage and Jeevan Chalke, tested by Kashif Zeeshan. --- README.md | 7 ++ expected/aggregate_pushdown.out | 149 ++++++++++++++++++++++++++++++ expected/aggregate_pushdown_1.out | 149 ++++++++++++++++++++++++++++++ expected/aggregate_pushdown_2.out | 149 ++++++++++++++++++++++++++++++ mongo_fdw.c | 25 ++++- mongo_fdw.h | 6 +- option.c | 8 +- sql/aggregate_pushdown.sql | 51 ++++++++++ 8 files changed, 538 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 8044136..fa34f76 100644 --- a/README.md +++ b/README.md @@ -274,6 +274,11 @@ The following options are only supported with meta driver: join has set it to false then the join will not be pushed down. The table-level value of the option takes precedence over the server-level option value. Default is `true`. + * `enable_aggregate_pushdown`: If `true`, push aggregates to the remote + MongoDB server instead of fetching all of the rows and aggregating them + locally. This option can also be set for an individual table. The + table-level value of the option takes precedence over the server-level + option value. Default is `true`. The following parameters can be set on a MongoDB foreign table object: @@ -283,6 +288,8 @@ The following parameters can be set on a MongoDB foreign table object: the foreign table name used in the relevant `CREATE` command. * `enable_join_pushdown`: Similar to the server-level option, but can be configured at table level as well. Default is `true`. + * `enable_aggregate_pushdown`: Similar to the server-level option, but + can be configured at table level as well. Default is `true`. The following parameters can be supplied while creating user mapping: diff --git a/expected/aggregate_pushdown.out b/expected/aggregate_pushdown.out index e24caa0..5978943 100644 --- a/expected/aggregate_pushdown.out +++ b/expected/aggregate_pushdown.out @@ -1133,6 +1133,155 @@ SELECT c1, count(t1) FROM fprt1 t1 GROUP BY c1 HAVING avg(c2) < 22 ORDER BY 1; (8 rows) SET enable_partitionwise_aggregate TO OFF; +-- Support enable_aggregate_pushdown option at server level and table level. +-- Check only boolean values are accepted. +ALTER SERVER mongo_server OPTIONS (ADD enable_aggregate_pushdown 'non-bolean'); +ERROR: enable_aggregate_pushdown requires a Boolean value +-- Test the option at server level. +ALTER SERVER mongo_server OPTIONS (ADD enable_aggregate_pushdown 'false'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT count(*) FROM fdw137_t1 GROUP BY c1 HAVING min(c1) > 500 ORDER BY 1; + QUERY PLAN +-------------------------------------------------------------- + Sort + Output: (count(*)), c1 + Sort Key: (count(*)) + -> HashAggregate + Output: count(*), c1 + Group Key: fdw137_t1.c1 + Filter: (min(fdw137_t1.c1) > 500) + -> Foreign Scan on public.fdw137_t1 + Output: _id, c1, c2, c3, c4, c5, c6, c7, c8 + Foreign Namespace: mongo_fdw_regress.test_tbl1 +(10 rows) + +ALTER SERVER mongo_server OPTIONS (SET enable_aggregate_pushdown 'true'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT count(*) FROM fdw137_t1 GROUP BY c1 HAVING min(c1) > 500 ORDER BY 1; + QUERY PLAN +--------------------------------------------------------------------------------- + Sort + Output: (count(*)), c1 + Sort Key: (count(*)) + -> Foreign Scan + Output: (count(*)), c1 + Foreign Namespace: Aggregate on (mongo_fdw_regress.test_tbl1 fdw137_t1) +(6 rows) + +-- Test the option at table level. Setting option at table level does not +-- affect the setting at server level. +ALTER FOREIGN TABLE fdw137_t1 OPTIONS (ADD enable_aggregate_pushdown 'false'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT count(*) FROM fdw137_t1 GROUP BY c1 HAVING min(c1) > 500 ORDER BY 1; + QUERY PLAN +-------------------------------------------------------------- + Sort + Output: (count(*)), c1 + Sort Key: (count(*)) + -> HashAggregate + Output: count(*), c1 + Group Key: fdw137_t1.c1 + Filter: (min(fdw137_t1.c1) > 500) + -> Foreign Scan on public.fdw137_t1 + Output: _id, c1, c2, c3, c4, c5, c6, c7, c8 + Foreign Namespace: mongo_fdw_regress.test_tbl1 +(10 rows) + +ALTER SERVER mongo_server OPTIONS (SET enable_aggregate_pushdown 'false'); +ALTER FOREIGN TABLE fdw137_t1 OPTIONS (SET enable_aggregate_pushdown 'true'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT count(*) FROM fdw137_t1 GROUP BY c1 HAVING min(c1) > 500 ORDER BY 1; + QUERY PLAN +--------------------------------------------------------------------------------- + Sort + Output: (count(*)), c1 + Sort Key: (count(*)) + -> Foreign Scan + Output: (count(*)), c1 + Foreign Namespace: Aggregate on (mongo_fdw_regress.test_tbl1 fdw137_t1) +(6 rows) + +-- Test option for aggregation over join. Allow aggregation only if enabled for +-- both the relations involved in the join. +ALTER SERVER mongo_server OPTIONS (SET enable_aggregate_pushdown 'true'); +ALTER FOREIGN TABLE fdw137_t1 OPTIONS (SET enable_aggregate_pushdown 'false'); +ALTER FOREIGN TABLE fdw137_t2 OPTIONS (ADD enable_aggregate_pushdown 'false'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(t2.c1), t1.c8 FROM fdw137_t1 t1 LEFT JOIN fdw137_t2 t2 ON (t1.c8 = t2.c1) GROUP BY t1.c8 ORDER BY 2; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------- + Sort + Output: (sum(t2.c1)), t1.c8 + Sort Key: t1.c8 + -> HashAggregate + Output: sum(t2.c1), t1.c8 + Group Key: t1.c8 + -> Foreign Scan + Output: t1.c8, t2.c1 + Foreign Namespace: (mongo_fdw_regress.test_tbl1 t1) LEFT JOIN (mongo_fdw_regress.test_tbl2 t2) +(9 rows) + +ALTER SERVER mongo_server OPTIONS (SET enable_aggregate_pushdown 'true'); +ALTER FOREIGN TABLE fdw137_t1 OPTIONS (SET enable_aggregate_pushdown 'true'); +ALTER FOREIGN TABLE fdw137_t2 OPTIONS (SET enable_aggregate_pushdown 'false'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(t2.c1), t1.c8 FROM fdw137_t1 t1 LEFT JOIN fdw137_t2 t2 ON (t1.c8 = t2.c1) GROUP BY t1.c8 ORDER BY 2; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------- + Sort + Output: (sum(t2.c1)), t1.c8 + Sort Key: t1.c8 + -> HashAggregate + Output: sum(t2.c1), t1.c8 + Group Key: t1.c8 + -> Foreign Scan + Output: t1.c8, t2.c1 + Foreign Namespace: (mongo_fdw_regress.test_tbl1 t1) LEFT JOIN (mongo_fdw_regress.test_tbl2 t2) +(9 rows) + +ALTER SERVER mongo_server OPTIONS (SET enable_aggregate_pushdown 'false'); +ALTER FOREIGN TABLE fdw137_t1 OPTIONS (SET enable_aggregate_pushdown 'true'); +ALTER FOREIGN TABLE fdw137_t2 OPTIONS (SET enable_aggregate_pushdown 'true'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(t2.c1), t1.c8 FROM fdw137_t1 t1 LEFT JOIN fdw137_t2 t2 ON (t1.c8 = t2.c1) GROUP BY t1.c8 ORDER BY 2; + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- + Sort + Output: (sum(t2.c1)), t1.c8 + Sort Key: t1.c8 + -> Foreign Scan + Output: (sum(t2.c1)), t1.c8 + Foreign Namespace: Aggregate on ((mongo_fdw_regress.test_tbl1 t1) LEFT JOIN (mongo_fdw_regress.test_tbl2 t2)) +(6 rows) + +-- Check when enable_join_pushdown is OFF and enable_aggregate_pushdown is ON. +-- Shouldn't push down join as well as aggregation. +ALTER SERVER mongo_server OPTIONS (ADD enable_join_pushdown 'false'); +ALTER SERVER mongo_server OPTIONS (SET enable_aggregate_pushdown 'true'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(t2.c1), t1.c8 FROM fdw137_t1 t1 LEFT JOIN fdw137_t2 t2 ON (t1.c8 = t2.c1) GROUP BY t1.c8 ORDER BY 2; + QUERY PLAN +-------------------------------------------------------------------- + GroupAggregate + Output: sum(t2.c1), t1.c8 + Group Key: t1.c8 + -> Merge Left Join + Output: t1.c8, t2.c1 + Merge Cond: (t1.c8 = t2.c1) + -> Sort + Output: t1.c8 + Sort Key: t1.c8 + -> Foreign Scan on public.fdw137_t1 t1 + Output: t1.c8 + Foreign Namespace: mongo_fdw_regress.test_tbl1 + -> Sort + Output: t2.c1 + Sort Key: t2.c1 + -> Foreign Scan on public.fdw137_t2 t2 + Output: t2.c1 + Foreign Namespace: mongo_fdw_regress.test_tbl2 +(18 rows) + -- Cleanup DELETE FROM fdw137_t1 WHERE c8 IS NULL; DELETE FROM fdw137_t1 WHERE c8 = 60; diff --git a/expected/aggregate_pushdown_1.out b/expected/aggregate_pushdown_1.out index 6901b49..fe097ec 100644 --- a/expected/aggregate_pushdown_1.out +++ b/expected/aggregate_pushdown_1.out @@ -1133,6 +1133,155 @@ SELECT c1, count(t1) FROM fprt1 t1 GROUP BY c1 HAVING avg(c2) < 22 ORDER BY 1; (8 rows) SET enable_partitionwise_aggregate TO OFF; +-- Support enable_aggregate_pushdown option at server level and table level. +-- Check only boolean values are accepted. +ALTER SERVER mongo_server OPTIONS (ADD enable_aggregate_pushdown 'non-bolean'); +ERROR: enable_aggregate_pushdown requires a Boolean value +-- Test the option at server level. +ALTER SERVER mongo_server OPTIONS (ADD enable_aggregate_pushdown 'false'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT count(*) FROM fdw137_t1 GROUP BY c1 HAVING min(c1) > 500 ORDER BY 1; + QUERY PLAN +-------------------------------------------------------------- + Sort + Output: (count(*)), c1 + Sort Key: (count(*)) + -> HashAggregate + Output: count(*), c1 + Group Key: fdw137_t1.c1 + Filter: (min(fdw137_t1.c1) > 500) + -> Foreign Scan on public.fdw137_t1 + Output: _id, c1, c2, c3, c4, c5, c6, c7, c8 + Foreign Namespace: mongo_fdw_regress.test_tbl1 +(10 rows) + +ALTER SERVER mongo_server OPTIONS (SET enable_aggregate_pushdown 'true'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT count(*) FROM fdw137_t1 GROUP BY c1 HAVING min(c1) > 500 ORDER BY 1; + QUERY PLAN +--------------------------------------------------------------------------------- + Sort + Output: (count(*)), c1 + Sort Key: (count(*)) + -> Foreign Scan + Output: (count(*)), c1 + Foreign Namespace: Aggregate on (mongo_fdw_regress.test_tbl1 fdw137_t1) +(6 rows) + +-- Test the option at table level. Setting option at table level does not +-- affect the setting at server level. +ALTER FOREIGN TABLE fdw137_t1 OPTIONS (ADD enable_aggregate_pushdown 'false'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT count(*) FROM fdw137_t1 GROUP BY c1 HAVING min(c1) > 500 ORDER BY 1; + QUERY PLAN +-------------------------------------------------------------- + Sort + Output: (count(*)), c1 + Sort Key: (count(*)) + -> HashAggregate + Output: count(*), c1 + Group Key: fdw137_t1.c1 + Filter: (min(fdw137_t1.c1) > 500) + -> Foreign Scan on public.fdw137_t1 + Output: _id, c1, c2, c3, c4, c5, c6, c7, c8 + Foreign Namespace: mongo_fdw_regress.test_tbl1 +(10 rows) + +ALTER SERVER mongo_server OPTIONS (SET enable_aggregate_pushdown 'false'); +ALTER FOREIGN TABLE fdw137_t1 OPTIONS (SET enable_aggregate_pushdown 'true'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT count(*) FROM fdw137_t1 GROUP BY c1 HAVING min(c1) > 500 ORDER BY 1; + QUERY PLAN +--------------------------------------------------------------------------------- + Sort + Output: (count(*)), c1 + Sort Key: (count(*)) + -> Foreign Scan + Output: (count(*)), c1 + Foreign Namespace: Aggregate on (mongo_fdw_regress.test_tbl1 fdw137_t1) +(6 rows) + +-- Test option for aggregation over join. Allow aggregation only if enabled for +-- both the relations involved in the join. +ALTER SERVER mongo_server OPTIONS (SET enable_aggregate_pushdown 'true'); +ALTER FOREIGN TABLE fdw137_t1 OPTIONS (SET enable_aggregate_pushdown 'false'); +ALTER FOREIGN TABLE fdw137_t2 OPTIONS (ADD enable_aggregate_pushdown 'false'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(t2.c1), t1.c8 FROM fdw137_t1 t1 LEFT JOIN fdw137_t2 t2 ON (t1.c8 = t2.c1) GROUP BY t1.c8 ORDER BY 2; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------- + Sort + Output: (sum(t2.c1)), t1.c8 + Sort Key: t1.c8 + -> HashAggregate + Output: sum(t2.c1), t1.c8 + Group Key: t1.c8 + -> Foreign Scan + Output: t1.c8, t2.c1 + Foreign Namespace: (mongo_fdw_regress.test_tbl1 t1) LEFT JOIN (mongo_fdw_regress.test_tbl2 t2) +(9 rows) + +ALTER SERVER mongo_server OPTIONS (SET enable_aggregate_pushdown 'true'); +ALTER FOREIGN TABLE fdw137_t1 OPTIONS (SET enable_aggregate_pushdown 'true'); +ALTER FOREIGN TABLE fdw137_t2 OPTIONS (SET enable_aggregate_pushdown 'false'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(t2.c1), t1.c8 FROM fdw137_t1 t1 LEFT JOIN fdw137_t2 t2 ON (t1.c8 = t2.c1) GROUP BY t1.c8 ORDER BY 2; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------- + Sort + Output: (sum(t2.c1)), t1.c8 + Sort Key: t1.c8 + -> HashAggregate + Output: sum(t2.c1), t1.c8 + Group Key: t1.c8 + -> Foreign Scan + Output: t1.c8, t2.c1 + Foreign Namespace: (mongo_fdw_regress.test_tbl1 t1) LEFT JOIN (mongo_fdw_regress.test_tbl2 t2) +(9 rows) + +ALTER SERVER mongo_server OPTIONS (SET enable_aggregate_pushdown 'false'); +ALTER FOREIGN TABLE fdw137_t1 OPTIONS (SET enable_aggregate_pushdown 'true'); +ALTER FOREIGN TABLE fdw137_t2 OPTIONS (SET enable_aggregate_pushdown 'true'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(t2.c1), t1.c8 FROM fdw137_t1 t1 LEFT JOIN fdw137_t2 t2 ON (t1.c8 = t2.c1) GROUP BY t1.c8 ORDER BY 2; + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- + Sort + Output: (sum(t2.c1)), t1.c8 + Sort Key: t1.c8 + -> Foreign Scan + Output: (sum(t2.c1)), t1.c8 + Foreign Namespace: Aggregate on ((mongo_fdw_regress.test_tbl1 t1) LEFT JOIN (mongo_fdw_regress.test_tbl2 t2)) +(6 rows) + +-- Check when enable_join_pushdown is OFF and enable_aggregate_pushdown is ON. +-- Shouldn't push down join as well as aggregation. +ALTER SERVER mongo_server OPTIONS (ADD enable_join_pushdown 'false'); +ALTER SERVER mongo_server OPTIONS (SET enable_aggregate_pushdown 'true'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(t2.c1), t1.c8 FROM fdw137_t1 t1 LEFT JOIN fdw137_t2 t2 ON (t1.c8 = t2.c1) GROUP BY t1.c8 ORDER BY 2; + QUERY PLAN +-------------------------------------------------------------------- + GroupAggregate + Output: sum(t2.c1), t1.c8 + Group Key: t1.c8 + -> Merge Left Join + Output: t1.c8, t2.c1 + Merge Cond: (t1.c8 = t2.c1) + -> Sort + Output: t1.c8 + Sort Key: t1.c8 + -> Foreign Scan on public.fdw137_t1 t1 + Output: t1.c8 + Foreign Namespace: mongo_fdw_regress.test_tbl1 + -> Sort + Output: t2.c1 + Sort Key: t2.c1 + -> Foreign Scan on public.fdw137_t2 t2 + Output: t2.c1 + Foreign Namespace: mongo_fdw_regress.test_tbl2 +(18 rows) + -- Cleanup DELETE FROM fdw137_t1 WHERE c8 IS NULL; DELETE FROM fdw137_t1 WHERE c8 = 60; diff --git a/expected/aggregate_pushdown_2.out b/expected/aggregate_pushdown_2.out index 74a0bbb..9381f6c 100644 --- a/expected/aggregate_pushdown_2.out +++ b/expected/aggregate_pushdown_2.out @@ -1138,6 +1138,155 @@ SELECT c1, count(t1) FROM fprt1 t1 GROUP BY c1 HAVING avg(c2) < 22 ORDER BY 1; SET enable_partitionwise_aggregate TO OFF; ERROR: unrecognized configuration parameter "enable_partitionwise_aggregate" +-- Support enable_aggregate_pushdown option at server level and table level. +-- Check only boolean values are accepted. +ALTER SERVER mongo_server OPTIONS (ADD enable_aggregate_pushdown 'non-bolean'); +ERROR: enable_aggregate_pushdown requires a Boolean value +-- Test the option at server level. +ALTER SERVER mongo_server OPTIONS (ADD enable_aggregate_pushdown 'false'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT count(*) FROM fdw137_t1 GROUP BY c1 HAVING min(c1) > 500 ORDER BY 1; + QUERY PLAN +-------------------------------------------------------------- + Sort + Output: (count(*)), c1 + Sort Key: (count(*)) + -> HashAggregate + Output: count(*), c1 + Group Key: fdw137_t1.c1 + Filter: (min(fdw137_t1.c1) > 500) + -> Foreign Scan on public.fdw137_t1 + Output: _id, c1, c2, c3, c4, c5, c6, c7, c8 + Foreign Namespace: mongo_fdw_regress.test_tbl1 +(10 rows) + +ALTER SERVER mongo_server OPTIONS (SET enable_aggregate_pushdown 'true'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT count(*) FROM fdw137_t1 GROUP BY c1 HAVING min(c1) > 500 ORDER BY 1; + QUERY PLAN +--------------------------------------------------------------------------------- + Sort + Output: (count(*)), c1 + Sort Key: (count(*)) + -> Foreign Scan + Output: (count(*)), c1 + Foreign Namespace: Aggregate on (mongo_fdw_regress.test_tbl1 fdw137_t1) +(6 rows) + +-- Test the option at table level. Setting option at table level does not +-- affect the setting at server level. +ALTER FOREIGN TABLE fdw137_t1 OPTIONS (ADD enable_aggregate_pushdown 'false'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT count(*) FROM fdw137_t1 GROUP BY c1 HAVING min(c1) > 500 ORDER BY 1; + QUERY PLAN +-------------------------------------------------------------- + Sort + Output: (count(*)), c1 + Sort Key: (count(*)) + -> HashAggregate + Output: count(*), c1 + Group Key: fdw137_t1.c1 + Filter: (min(fdw137_t1.c1) > 500) + -> Foreign Scan on public.fdw137_t1 + Output: _id, c1, c2, c3, c4, c5, c6, c7, c8 + Foreign Namespace: mongo_fdw_regress.test_tbl1 +(10 rows) + +ALTER SERVER mongo_server OPTIONS (SET enable_aggregate_pushdown 'false'); +ALTER FOREIGN TABLE fdw137_t1 OPTIONS (SET enable_aggregate_pushdown 'true'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT count(*) FROM fdw137_t1 GROUP BY c1 HAVING min(c1) > 500 ORDER BY 1; + QUERY PLAN +--------------------------------------------------------------------------------- + Sort + Output: (count(*)), c1 + Sort Key: (count(*)) + -> Foreign Scan + Output: (count(*)), c1 + Foreign Namespace: Aggregate on (mongo_fdw_regress.test_tbl1 fdw137_t1) +(6 rows) + +-- Test option for aggregation over join. Allow aggregation only if enabled for +-- both the relations involved in the join. +ALTER SERVER mongo_server OPTIONS (SET enable_aggregate_pushdown 'true'); +ALTER FOREIGN TABLE fdw137_t1 OPTIONS (SET enable_aggregate_pushdown 'false'); +ALTER FOREIGN TABLE fdw137_t2 OPTIONS (ADD enable_aggregate_pushdown 'false'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(t2.c1), t1.c8 FROM fdw137_t1 t1 LEFT JOIN fdw137_t2 t2 ON (t1.c8 = t2.c1) GROUP BY t1.c8 ORDER BY 2; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------- + Sort + Output: (sum(t2.c1)), t1.c8 + Sort Key: t1.c8 + -> HashAggregate + Output: sum(t2.c1), t1.c8 + Group Key: t1.c8 + -> Foreign Scan + Output: t1.c8, t2.c1 + Foreign Namespace: (mongo_fdw_regress.test_tbl1 t1) LEFT JOIN (mongo_fdw_regress.test_tbl2 t2) +(9 rows) + +ALTER SERVER mongo_server OPTIONS (SET enable_aggregate_pushdown 'true'); +ALTER FOREIGN TABLE fdw137_t1 OPTIONS (SET enable_aggregate_pushdown 'true'); +ALTER FOREIGN TABLE fdw137_t2 OPTIONS (SET enable_aggregate_pushdown 'false'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(t2.c1), t1.c8 FROM fdw137_t1 t1 LEFT JOIN fdw137_t2 t2 ON (t1.c8 = t2.c1) GROUP BY t1.c8 ORDER BY 2; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------- + Sort + Output: (sum(t2.c1)), t1.c8 + Sort Key: t1.c8 + -> HashAggregate + Output: sum(t2.c1), t1.c8 + Group Key: t1.c8 + -> Foreign Scan + Output: t1.c8, t2.c1 + Foreign Namespace: (mongo_fdw_regress.test_tbl1 t1) LEFT JOIN (mongo_fdw_regress.test_tbl2 t2) +(9 rows) + +ALTER SERVER mongo_server OPTIONS (SET enable_aggregate_pushdown 'false'); +ALTER FOREIGN TABLE fdw137_t1 OPTIONS (SET enable_aggregate_pushdown 'true'); +ALTER FOREIGN TABLE fdw137_t2 OPTIONS (SET enable_aggregate_pushdown 'true'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(t2.c1), t1.c8 FROM fdw137_t1 t1 LEFT JOIN fdw137_t2 t2 ON (t1.c8 = t2.c1) GROUP BY t1.c8 ORDER BY 2; + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- + Sort + Output: (sum(t2.c1)), t1.c8 + Sort Key: t1.c8 + -> Foreign Scan + Output: (sum(t2.c1)), t1.c8 + Foreign Namespace: Aggregate on ((mongo_fdw_regress.test_tbl1 t1) LEFT JOIN (mongo_fdw_regress.test_tbl2 t2)) +(6 rows) + +-- Check when enable_join_pushdown is OFF and enable_aggregate_pushdown is ON. +-- Shouldn't push down join as well as aggregation. +ALTER SERVER mongo_server OPTIONS (ADD enable_join_pushdown 'false'); +ALTER SERVER mongo_server OPTIONS (SET enable_aggregate_pushdown 'true'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(t2.c1), t1.c8 FROM fdw137_t1 t1 LEFT JOIN fdw137_t2 t2 ON (t1.c8 = t2.c1) GROUP BY t1.c8 ORDER BY 2; + QUERY PLAN +-------------------------------------------------------------------- + GroupAggregate + Output: sum(t2.c1), t1.c8 + Group Key: t1.c8 + -> Merge Left Join + Output: t1.c8, t2.c1 + Merge Cond: (t1.c8 = t2.c1) + -> Sort + Output: t1.c8 + Sort Key: t1.c8 + -> Foreign Scan on public.fdw137_t1 t1 + Output: t1.c8 + Foreign Namespace: mongo_fdw_regress.test_tbl1 + -> Sort + Output: t2.c1 + Sort Key: t2.c1 + -> Foreign Scan on public.fdw137_t2 t2 + Output: t2.c1 + Foreign Namespace: mongo_fdw_regress.test_tbl2 +(18 rows) + -- Cleanup DELETE FROM fdw137_t1 WHERE c8 IS NULL; DELETE FROM fdw137_t1 WHERE c8 = 60; diff --git a/mongo_fdw.c b/mongo_fdw.c index 801391d..f7b9b79 100644 --- a/mongo_fdw.c +++ b/mongo_fdw.c @@ -3322,18 +3322,35 @@ mongo_foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel) PathTarget *grouping_target = root->upper_targets[UPPERREL_GROUP_AGG]; #endif MongoFdwRelationInfo *fpinfo = (MongoFdwRelationInfo *) grouped_rel->fdw_private; - MongoFdwRelationInfo *ofpinfo; + MongoFdwRelationInfo *ofpinfo = (MongoFdwRelationInfo *) fpinfo->outerrel->fdw_private; + MongoFdwRelationInfo *ofpinfo_o; + MongoFdwRelationInfo *ofpinfo_i; ListCell *lc; int i; List *tlist = NIL; + bool is_join = false; + + /* + * If the underlying scan relation is the join relation then find the + * fpinfo of each relation involved in the join. + */ + if (IS_JOIN_REL(fpinfo->outerrel)) + { + ofpinfo_o = (MongoFdwRelationInfo *) ofpinfo->outerrel->fdw_private; + ofpinfo_i = (MongoFdwRelationInfo *) ofpinfo->innerrel->fdw_private; + is_join = true; + } + + /* If aggregate pushdown is not enabled, honor it. */ + if ((!is_join && !ofpinfo->options->enable_aggregate_pushdown) || + ((is_join && !ofpinfo_o->options->enable_aggregate_pushdown) || + (is_join && !ofpinfo_i->options->enable_aggregate_pushdown))) + return false; /* Grouping Sets are not pushable */ if (query->groupingSets) return false; - /* Get the fpinfo of the underlying scan relation. */ - ofpinfo = (MongoFdwRelationInfo *) fpinfo->outerrel->fdw_private; - /* * If underneath input relation has any local conditions, those conditions * are required to be applied before performing aggregation. Hence the diff --git a/mongo_fdw.h b/mongo_fdw.h index f129494..31c4858 100644 --- a/mongo_fdw.h +++ b/mongo_fdw.h @@ -157,6 +157,7 @@ #define OPTION_NAME_CRL_FILE "crl_file" #define OPTION_NAME_WEAK_CERT "weak_cert_validation" #define OPTION_NAME_ENABLE_JOIN_PUSHDOWN "enable_join_pushdown" +#define OPTION_NAME_ENABLE_AGGREGATE_PUSHDOWN "enable_aggregate_pushdown" #endif /* Default values for option parameters */ @@ -202,7 +203,7 @@ typedef struct MongoValidOption /* Array of options that are valid for mongo_fdw */ #ifdef META_DRIVER -static const uint32 ValidOptionCount = 19; +static const uint32 ValidOptionCount = 21; #else static const uint32 ValidOptionCount = 7; #endif @@ -225,6 +226,7 @@ static const MongoValidOption ValidOptionArray[] = {OPTION_NAME_CRL_FILE, ForeignServerRelationId}, {OPTION_NAME_WEAK_CERT, ForeignServerRelationId}, {OPTION_NAME_ENABLE_JOIN_PUSHDOWN, ForeignServerRelationId}, + {OPTION_NAME_ENABLE_AGGREGATE_PUSHDOWN, ForeignServerRelationId}, #endif /* Foreign table options */ @@ -232,6 +234,7 @@ static const MongoValidOption ValidOptionArray[] = {OPTION_NAME_COLLECTION, ForeignTableRelationId}, #ifdef META_DRIVER {OPTION_NAME_ENABLE_JOIN_PUSHDOWN, ForeignTableRelationId}, + {OPTION_NAME_ENABLE_AGGREGATE_PUSHDOWN, ForeignTableRelationId}, #endif /* User mapping options */ @@ -265,6 +268,7 @@ typedef struct MongoFdwOptions char *crl_file; bool weak_cert_validation; bool enable_join_pushdown; + bool enable_aggregate_pushdown; #endif } MongoFdwOptions; diff --git a/option.c b/option.c index 9fc6168..36d2fd6 100644 --- a/option.c +++ b/option.c @@ -109,7 +109,8 @@ mongo_fdw_validator(PG_FUNCTION_ARGS) #ifdef META_DRIVER || strcmp(optionName, OPTION_NAME_WEAK_CERT) == 0 || strcmp(optionName, OPTION_NAME_ENABLE_JOIN_PUSHDOWN) == 0 || - strcmp(optionName, OPTION_NAME_SSL) == 0 + strcmp(optionName, OPTION_NAME_SSL) == 0 || + strcmp(optionName, OPTION_NAME_ENABLE_AGGREGATE_PUSHDOWN) == 0 #endif ) { @@ -186,6 +187,7 @@ mongo_get_options(Oid foreignTableId) options->ssl = false; options->weak_cert_validation = false; options->enable_join_pushdown = true; + options->enable_aggregate_pushdown = true; #endif /* Loop through the options */ @@ -227,6 +229,10 @@ mongo_get_options(Oid foreignTableId) else if (strcmp(def->defname, OPTION_NAME_ENABLE_JOIN_PUSHDOWN) == 0) options->enable_join_pushdown = defGetBoolean(def); + else if (strcmp(def->defname, + OPTION_NAME_ENABLE_AGGREGATE_PUSHDOWN) == 0) + options->enable_aggregate_pushdown = defGetBoolean(def); + else /* This is for continuation */ #endif diff --git a/sql/aggregate_pushdown.sql b/sql/aggregate_pushdown.sql index d99e7c3..30ed550 100644 --- a/sql/aggregate_pushdown.sql +++ b/sql/aggregate_pushdown.sql @@ -252,6 +252,57 @@ SELECT c1, count(t1) FROM fprt1 t1 GROUP BY c1 HAVING avg(c2) < 22 ORDER BY 1; SET enable_partitionwise_aggregate TO OFF; +-- Support enable_aggregate_pushdown option at server level and table level. +-- Check only boolean values are accepted. +ALTER SERVER mongo_server OPTIONS (ADD enable_aggregate_pushdown 'non-bolean'); + +-- Test the option at server level. +ALTER SERVER mongo_server OPTIONS (ADD enable_aggregate_pushdown 'false'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT count(*) FROM fdw137_t1 GROUP BY c1 HAVING min(c1) > 500 ORDER BY 1; + +ALTER SERVER mongo_server OPTIONS (SET enable_aggregate_pushdown 'true'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT count(*) FROM fdw137_t1 GROUP BY c1 HAVING min(c1) > 500 ORDER BY 1; + +-- Test the option at table level. Setting option at table level does not +-- affect the setting at server level. +ALTER FOREIGN TABLE fdw137_t1 OPTIONS (ADD enable_aggregate_pushdown 'false'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT count(*) FROM fdw137_t1 GROUP BY c1 HAVING min(c1) > 500 ORDER BY 1; + +ALTER SERVER mongo_server OPTIONS (SET enable_aggregate_pushdown 'false'); +ALTER FOREIGN TABLE fdw137_t1 OPTIONS (SET enable_aggregate_pushdown 'true'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT count(*) FROM fdw137_t1 GROUP BY c1 HAVING min(c1) > 500 ORDER BY 1; + +-- Test option for aggregation over join. Allow aggregation only if enabled for +-- both the relations involved in the join. +ALTER SERVER mongo_server OPTIONS (SET enable_aggregate_pushdown 'true'); +ALTER FOREIGN TABLE fdw137_t1 OPTIONS (SET enable_aggregate_pushdown 'false'); +ALTER FOREIGN TABLE fdw137_t2 OPTIONS (ADD enable_aggregate_pushdown 'false'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(t2.c1), t1.c8 FROM fdw137_t1 t1 LEFT JOIN fdw137_t2 t2 ON (t1.c8 = t2.c1) GROUP BY t1.c8 ORDER BY 2; + +ALTER SERVER mongo_server OPTIONS (SET enable_aggregate_pushdown 'true'); +ALTER FOREIGN TABLE fdw137_t1 OPTIONS (SET enable_aggregate_pushdown 'true'); +ALTER FOREIGN TABLE fdw137_t2 OPTIONS (SET enable_aggregate_pushdown 'false'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(t2.c1), t1.c8 FROM fdw137_t1 t1 LEFT JOIN fdw137_t2 t2 ON (t1.c8 = t2.c1) GROUP BY t1.c8 ORDER BY 2; + +ALTER SERVER mongo_server OPTIONS (SET enable_aggregate_pushdown 'false'); +ALTER FOREIGN TABLE fdw137_t1 OPTIONS (SET enable_aggregate_pushdown 'true'); +ALTER FOREIGN TABLE fdw137_t2 OPTIONS (SET enable_aggregate_pushdown 'true'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(t2.c1), t1.c8 FROM fdw137_t1 t1 LEFT JOIN fdw137_t2 t2 ON (t1.c8 = t2.c1) GROUP BY t1.c8 ORDER BY 2; + +-- Check when enable_join_pushdown is OFF and enable_aggregate_pushdown is ON. +-- Shouldn't push down join as well as aggregation. +ALTER SERVER mongo_server OPTIONS (ADD enable_join_pushdown 'false'); +ALTER SERVER mongo_server OPTIONS (SET enable_aggregate_pushdown 'true'); +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(t2.c1), t1.c8 FROM fdw137_t1 t1 LEFT JOIN fdw137_t2 t2 ON (t1.c8 = t2.c1) GROUP BY t1.c8 ORDER BY 2; + -- Cleanup DELETE FROM fdw137_t1 WHERE c8 IS NULL; DELETE FROM fdw137_t1 WHERE c8 = 60;