Skip to content

Commit 58b9b19

Browse files
committed
[AQUMV] Compute Aggregations on Materialized Views.
Support origin query has aggregations, compute Aggregations on materilized views whose query don't have Aggegations itself. create incremental materialized view mv as select c1 as mc1, c2 as mc2, c3 as mc3 from t1 where c1 > 90; Origin query: select count(c1)+1, sum(c2) filter (where c2 > 95), stddev(c3) from t1 where c1 > 90; Could be rewritten to: select count(mc1)+1, sum(mc2) filter (where mc2 > 95), stddev(mc3) from mv; All aggregate functions including count(*) are supported in AQUMV which is not limited to IVM's current aggregate functions: count, sum, avg. Complex expressions have aggregations, and aggregations with Filter clause are also supported. Authored-by: Zhang Mingli avamingli@gmail.com
1 parent 5f9190e commit 58b9b19

4 files changed

Lines changed: 342 additions & 8 deletions

File tree

src/backend/optimizer/README.cbdb.aqumv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ AQUMV_MVP
220220
---------
221221
Support SELECT FROM a single relation both for mv_query and the origin_query.
222222
Below are not supported now:
223-
AGG
223+
Aggregation (on mv_query)
224224
Subquery
225225
Order by(for origin_query)
226226
Join

src/backend/optimizer/plan/aqumv.c

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
/*-------------------------------------------------------------------------
32
*
43
* aqumv.c
@@ -112,11 +111,11 @@ answer_query_using_materialized_views(PlannerInfo *root, RelOptInfo *current_rel
112111

113112
bool can_not_use_mv = (parse->commandType != CMD_SELECT) ||
114113
(parse->rowMarks != NIL) ||
115-
parse->hasAggs ||
116114
parse->hasWindowFuncs ||
117115
parse->hasDistinctOn ||
118116
/* Group By without agg could be possible though IMMV doesn't support it yet. */
119117
(parse->groupClause != NIL) ||
118+
(parse->havingQual != NULL) ||
120119
parse->hasModifyingCTE ||
121120
parse->sortClause ||
122121
(parse->parentStmtType == PARENTSTMTTYPE_REFRESH_MATVIEW) ||
@@ -277,8 +276,11 @@ answer_query_using_materialized_views(PlannerInfo *root, RelOptInfo *current_rel
277276
subroot->plan_params = NIL;
278277
subroot->outer_params = NULL;
279278
subroot->init_plans = NIL;
280-
subroot->agginfos = NIL;
281-
subroot->aggtransinfos = NIL;
279+
if (!parse->hasAggs)
280+
{
281+
subroot->agginfos = NIL;
282+
subroot->aggtransinfos = NIL;
283+
}
282284
subroot->parse = mvQuery;
283285

284286
/*
@@ -335,6 +337,13 @@ answer_query_using_materialized_views(PlannerInfo *root, RelOptInfo *current_rel
335337
if(!aqumv_process_targetlist(context, parse->targetList, &mv_final_tlist))
336338
continue;
337339

340+
/*
341+
* We have successfully processed target list, all columns in Aggrefs could be
342+
* computed from mvQuery.
343+
* It's safe to set hasAggs here.
344+
*/
345+
mvQuery->hasAggs = parse->hasAggs;
346+
338347
/*
339348
* AQUMV
340349
* Process all quals to conjunctive normal form.
@@ -459,6 +468,10 @@ aqumv_init_context(List *view_tlist, List *mv_tlist)
459468
{
460469
i++;
461470
TargetEntry* tle = lfirst_node(TargetEntry, lc);
471+
472+
if (tle->resjunk)
473+
continue;
474+
462475
expr = tle->expr;
463476
if(IsA(expr, Var))
464477
{
@@ -478,8 +491,6 @@ aqumv_init_context(List *view_tlist, List *mv_tlist)
478491
return context;
479492
}
480493

481-
482-
483494
/*
484495
* Process varno after we eliminate mv's actions("old" and "new" relation)
485496
* Correct rindex and all varnos with a delta.
@@ -724,8 +735,9 @@ static Node *aqumv_adjust_sub_matched_expr_mutator(Node *node, aqumv_equivalent_
724735
PVC_RECURSE_WINDOWFUNCS |
725736
PVC_INCLUDE_PLACEHOLDERS);
726737

738+
/* Keep TargetEntry expr no changed in case for count(*). */
727739
if (expr_vars == NIL)
728-
return (Node *)node_expr;
740+
return is_targetEntry ? node : (Node *)node_expr;
729741
list_free(expr_vars);
730742

731743
/* Try match with mv_pure_vars_index, but do not disturb already rewrited exprs(Var->location = -2) */

src/test/regress/expected/aqumv.out

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,260 @@ select sqrt(abs(abs(c2) - c1 - 1) + abs(c2)) from aqumv_t1 where c1 > 30 and c1
731731
Optimizer: Postgres query optimizer
732732
(7 rows)
733733

734+
abort;
735+
--
736+
-- Support origin query with aggregations.
737+
-- Compute Aggregations from mv.
738+
--
739+
begin;
740+
create table aqumv_t2(c1 int, c2 int, c3 int) distributed by (c1);
741+
insert into aqumv_t2 select i, i+1, i+2 from generate_series(1, 100) i;
742+
insert into aqumv_t2 values (91, NULL, 95);
743+
analyze aqumv_t2;
744+
create incremental materialized view aqumv_mvt2_0 as
745+
select c1 as mc1, c2 as mc2, c3 as mc3
746+
from aqumv_t2 where c1 > 90;
747+
analyze aqumv_mvt2_0;
748+
-- test aggregation functions supported in IVM.
749+
set local enable_answer_query_using_materialized_views = off;
750+
explain(costs off, verbose)
751+
select count(c1), sum(c2), avg(c3) from aqumv_t2 where c1 > 90;
752+
QUERY PLAN
753+
-----------------------------------------------------------------------------------
754+
Finalize Aggregate
755+
Output: count(c1), sum(c2), avg(c3)
756+
-> Gather Motion 3:1 (slice1; segments: 3)
757+
Output: (PARTIAL count(c1)), (PARTIAL sum(c2)), (PARTIAL avg(c3))
758+
-> Partial Aggregate
759+
Output: PARTIAL count(c1), PARTIAL sum(c2), PARTIAL avg(c3)
760+
-> Seq Scan on public.aqumv_t2
761+
Output: c1, c2, c3
762+
Filter: (aqumv_t2.c1 > 90)
763+
Settings: enable_answer_query_using_materialized_views = 'off', optimizer = 'off'
764+
Optimizer: Postgres query optimizer
765+
(11 rows)
766+
767+
select count(c1), sum(c2), avg(c3) from aqumv_t2 where c1 > 90;
768+
count | sum | avg
769+
-------+-----+---------------------
770+
11 | 965 | 97.2727272727272727
771+
(1 row)
772+
773+
set local enable_answer_query_using_materialized_views = on;
774+
explain(costs off, verbose)
775+
select count(c1), sum(c2), avg(c3) from aqumv_t2 where c1 > 90;
776+
QUERY PLAN
777+
----------------------------------------------------------------------------------
778+
Finalize Aggregate
779+
Output: count(mc1), sum(mc2), avg(mc3)
780+
-> Gather Motion 3:1 (slice1; segments: 3)
781+
Output: (PARTIAL count(mc1)), (PARTIAL sum(mc2)), (PARTIAL avg(mc3))
782+
-> Partial Aggregate
783+
Output: PARTIAL count(mc1), PARTIAL sum(mc2), PARTIAL avg(mc3)
784+
-> Seq Scan on public.aqumv_mvt2_0
785+
Output: mc1, mc2, mc3
786+
Settings: enable_answer_query_using_materialized_views = 'on', optimizer = 'off'
787+
Optimizer: Postgres query optimizer
788+
(10 rows)
789+
790+
select count(c1), sum(c2), avg(c3) from aqumv_t2 where c1 > 90;
791+
count | sum | avg
792+
-------+-----+---------------------
793+
11 | 965 | 97.2727272727272727
794+
(1 row)
795+
796+
-- test complex expressions have AGG.
797+
set local enable_answer_query_using_materialized_views = off;
798+
explain(costs off, verbose)
799+
select count(c1) + 1 from aqumv_t2 where c1 > 90;
800+
QUERY PLAN
801+
-----------------------------------------------------------------------------------
802+
Finalize Aggregate
803+
Output: (count(c1) + 1)
804+
-> Gather Motion 3:1 (slice1; segments: 3)
805+
Output: (PARTIAL count(c1))
806+
-> Partial Aggregate
807+
Output: PARTIAL count(c1)
808+
-> Seq Scan on public.aqumv_t2
809+
Output: c1, c2, c3
810+
Filter: (aqumv_t2.c1 > 90)
811+
Settings: enable_answer_query_using_materialized_views = 'off', optimizer = 'off'
812+
Optimizer: Postgres query optimizer
813+
(11 rows)
814+
815+
select count(c1) + 1 from aqumv_t2 where c1 > 90;
816+
?column?
817+
----------
818+
12
819+
(1 row)
820+
821+
set local enable_answer_query_using_materialized_views = on;
822+
explain(costs off, verbose)
823+
select count(c1) + 1 from aqumv_t2 where c1 > 90;
824+
QUERY PLAN
825+
----------------------------------------------------------------------------------
826+
Finalize Aggregate
827+
Output: (count(mc1) + 1)
828+
-> Gather Motion 3:1 (slice1; segments: 3)
829+
Output: (PARTIAL count(mc1))
830+
-> Partial Aggregate
831+
Output: PARTIAL count(mc1)
832+
-> Seq Scan on public.aqumv_mvt2_0
833+
Output: mc1, mc2, mc3
834+
Settings: enable_answer_query_using_materialized_views = 'on', optimizer = 'off'
835+
Optimizer: Postgres query optimizer
836+
(10 rows)
837+
838+
select count(c1) + 1 from aqumv_t2 where c1 > 90;
839+
?column?
840+
----------
841+
12
842+
(1 row)
843+
844+
-- test AGG FILTER.
845+
set local enable_answer_query_using_materialized_views = off;
846+
explain(costs off, verbose)
847+
select sum(c2), sum(c2) filter (where c2 > 95) from aqumv_t2 where c1 > 90;
848+
QUERY PLAN
849+
-----------------------------------------------------------------------------------
850+
Finalize Aggregate
851+
Output: sum(c2), sum(c2) FILTER (WHERE (c2 > 95))
852+
-> Gather Motion 3:1 (slice1; segments: 3)
853+
Output: (PARTIAL sum(c2)), (PARTIAL sum(c2) FILTER (WHERE (c2 > 95)))
854+
-> Partial Aggregate
855+
Output: PARTIAL sum(c2), PARTIAL sum(c2) FILTER (WHERE (c2 > 95))
856+
-> Seq Scan on public.aqumv_t2
857+
Output: c1, c2, c3
858+
Filter: (aqumv_t2.c1 > 90)
859+
Settings: enable_answer_query_using_materialized_views = 'off', optimizer = 'off'
860+
Optimizer: Postgres query optimizer
861+
(11 rows)
862+
863+
select sum(c2), sum(c2) filter (where c2 > 95) from aqumv_t2 where c1 > 90;
864+
sum | sum
865+
-----+-----
866+
965 | 591
867+
(1 row)
868+
869+
set local enable_answer_query_using_materialized_views = on;
870+
explain(costs off, verbose)
871+
select sum(c2), sum(c2) filter (where c2 > 95) from aqumv_t2 where c1 > 90;
872+
QUERY PLAN
873+
------------------------------------------------------------------------------------
874+
Finalize Aggregate
875+
Output: sum(mc2), sum(mc2) FILTER (WHERE (mc2 > 95))
876+
-> Gather Motion 3:1 (slice1; segments: 3)
877+
Output: (PARTIAL sum(mc2)), (PARTIAL sum(mc2) FILTER (WHERE (mc2 > 95)))
878+
-> Partial Aggregate
879+
Output: PARTIAL sum(mc2), PARTIAL sum(mc2) FILTER (WHERE (mc2 > 95))
880+
-> Seq Scan on public.aqumv_mvt2_0
881+
Output: mc1, mc2, mc3
882+
Settings: enable_answer_query_using_materialized_views = 'on', optimizer = 'off'
883+
Optimizer: Postgres query optimizer
884+
(10 rows)
885+
886+
select sum(c2), sum(c2) filter (where c2 > 95) from aqumv_t2 where c1 > 90;
887+
sum | sum
888+
-----+-----
889+
965 | 591
890+
(1 row)
891+
892+
-- test AGG functions which are not supported in IVM now, but could work in AQUMV.
893+
set local enable_answer_query_using_materialized_views = off;
894+
explain(costs off, verbose)
895+
select max(c1), min(c3), stddev(c2) from aqumv_t2 where c1 > 90;
896+
QUERY PLAN
897+
-----------------------------------------------------------------------------------
898+
Finalize Aggregate
899+
Output: max(c1), min(c3), stddev(c2)
900+
-> Gather Motion 3:1 (slice1; segments: 3)
901+
Output: (PARTIAL max(c1)), (PARTIAL min(c3)), (PARTIAL stddev(c2))
902+
-> Partial Aggregate
903+
Output: PARTIAL max(c1), PARTIAL min(c3), PARTIAL stddev(c2)
904+
-> Seq Scan on public.aqumv_t2
905+
Output: c1, c2, c3
906+
Filter: (aqumv_t2.c1 > 90)
907+
Settings: enable_answer_query_using_materialized_views = 'off', optimizer = 'off'
908+
Optimizer: Postgres query optimizer
909+
(11 rows)
910+
911+
select max(c1), min(c3), stddev(c2) from aqumv_t2 where c1 > 90;
912+
max | min | stddev
913+
-----+-----+--------------------
914+
100 | 93 | 3.0276503540974917
915+
(1 row)
916+
917+
set local enable_answer_query_using_materialized_views = on;
918+
explain(costs off, verbose)
919+
select max(c1), min(c3), stddev(c2) from aqumv_t2 where c1 > 90;
920+
QUERY PLAN
921+
----------------------------------------------------------------------------------
922+
Finalize Aggregate
923+
Output: max(mc1), min(mc3), stddev(mc2)
924+
-> Gather Motion 3:1 (slice1; segments: 3)
925+
Output: (PARTIAL max(mc1)), (PARTIAL min(mc3)), (PARTIAL stddev(mc2))
926+
-> Partial Aggregate
927+
Output: PARTIAL max(mc1), PARTIAL min(mc3), PARTIAL stddev(mc2)
928+
-> Seq Scan on public.aqumv_mvt2_0
929+
Output: mc1, mc2, mc3
930+
Settings: enable_answer_query_using_materialized_views = 'on', optimizer = 'off'
931+
Optimizer: Postgres query optimizer
932+
(10 rows)
933+
934+
select max(c1), min(c3), stddev(c2) from aqumv_t2 where c1 > 90;
935+
max | min | stddev
936+
-----+-----+--------------------
937+
100 | 93 | 3.0276503540974917
938+
(1 row)
939+
940+
-- test count(*)
941+
set local enable_answer_query_using_materialized_views = off;
942+
explain(costs off, verbose)
943+
select count(c2), count(*) from aqumv_t2 where c1 > 90;
944+
QUERY PLAN
945+
-----------------------------------------------------------------------------------
946+
Finalize Aggregate
947+
Output: count(c2), count(*)
948+
-> Gather Motion 3:1 (slice1; segments: 3)
949+
Output: (PARTIAL count(c2)), (PARTIAL count(*))
950+
-> Partial Aggregate
951+
Output: PARTIAL count(c2), PARTIAL count(*)
952+
-> Seq Scan on public.aqumv_t2
953+
Output: c1, c2, c3
954+
Filter: (aqumv_t2.c1 > 90)
955+
Settings: enable_answer_query_using_materialized_views = 'off', optimizer = 'off'
956+
Optimizer: Postgres query optimizer
957+
(11 rows)
958+
959+
select count(c2), count(*) from aqumv_t2 where c1 > 90;
960+
count | count
961+
-------+-------
962+
10 | 11
963+
(1 row)
964+
965+
set local enable_answer_query_using_materialized_views = on;
966+
explain(costs off, verbose)
967+
select count(c2), count(*) from aqumv_t2 where c1 > 90;
968+
QUERY PLAN
969+
----------------------------------------------------------------------------------
970+
Finalize Aggregate
971+
Output: count(mc2), count(*)
972+
-> Gather Motion 3:1 (slice1; segments: 3)
973+
Output: (PARTIAL count(mc2)), (PARTIAL count(*))
974+
-> Partial Aggregate
975+
Output: PARTIAL count(mc2), PARTIAL count(*)
976+
-> Seq Scan on public.aqumv_mvt2_0
977+
Output: mc1, mc2, mc3
978+
Settings: enable_answer_query_using_materialized_views = 'on', optimizer = 'off'
979+
Optimizer: Postgres query optimizer
980+
(10 rows)
981+
982+
select count(c2), count(*) from aqumv_t2 where c1 > 90;
983+
count | count
984+
-------+-------
985+
10 | 11
986+
(1 row)
987+
734988
abort;
735989
reset optimizer;
736990
reset enable_answer_query_using_materialized_views;

0 commit comments

Comments
 (0)