Skip to content

Commit 52ead45

Browse files
avaminglimy-ship-it
authored andcommitted
[AQUMV] Allow to use normal materialized views to answer query.
As we have enabled materialized view data status maintenance, normal materialized views could also be used to answer query if their data status is up to date. There is no difference between IVM and normal materialized views to answer query. example, compute agg from a normal materialized view: create table t1(c1 int, c2 int, c3 int) distributed by (c1); create materialized view normal_mv_t1 as select c3 as mc3, c1 as mc1 from t1 where c1 > 90; set enable_answer_query_using_materialized_views = on; explain(costs off, verbose) select count(c3) from t1 where c1 > 90; QUERY PLAN ------------------------------------------------------ Finalize Aggregate Output: count(mc3) -> Gather Motion 3:1 (slice1; segments: 3) Output: (PARTIAL count(mc3)) -> Partial Aggregate Output: PARTIAL count(mc3) -> Seq Scan on aqumv.normal_mv_t1 Output: mc3, mc1 Optimizer: Postgres query optimizer Authored-by: Zhang Mingli avamingli@gmail.com
1 parent 7bda696 commit 52ead45

4 files changed

Lines changed: 168 additions & 4 deletions

File tree

src/backend/catalog/gp_matview_aux.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,9 @@ bool
421421
MatviewUsableForAppendAgg(Oid mvoid)
422422
{
423423
HeapTuple mvauxtup = SearchSysCacheCopy1(MVAUXOID, ObjectIdGetDatum(mvoid));
424+
if (!HeapTupleIsValid(mvauxtup))
425+
return false;
426+
424427
Form_gp_matview_aux auxform = (Form_gp_matview_aux) GETSTRUCT(mvauxtup);
425428
return ((auxform->datastatus == MV_DATA_STATUS_UP_TO_DATE) ||
426429
(auxform->datastatus == MV_DATA_STATUS_EXPIRED_INSERT_ONLY));
@@ -438,6 +441,11 @@ bool
438441
MatviewIsGeneralyUpToDate(Oid mvoid)
439442
{
440443
HeapTuple mvauxtup = SearchSysCacheCopy1(MVAUXOID, ObjectIdGetDatum(mvoid));
444+
445+
/* Not a candidate we recorded. */
446+
if (!HeapTupleIsValid(mvauxtup))
447+
return false;
448+
441449
Form_gp_matview_aux auxform = (Form_gp_matview_aux) GETSTRUCT(mvauxtup);
442450
return ((auxform->datastatus == MV_DATA_STATUS_UP_TO_DATE) ||
443451
(auxform->datastatus == MV_DATA_STATUS_UP_REORGANIZED));

src/backend/optimizer/plan/aqumv.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "access/htup_details.h"
1919
#include "access/table.h"
2020
#include "catalog/catalog.h"
21+
#include "catalog/gp_matview_aux.h"
2122
#include "catalog/pg_class_d.h"
2223
#include "catalog/pg_inherits.h"
2324
#include "catalog/pg_rewrite.h"
@@ -167,12 +168,18 @@ answer_query_using_materialized_views(PlannerInfo *root,
167168
matviewRel = table_open(rewrite_tup->ev_class, AccessShareLock);
168169
need_close = true;
169170

171+
if (!RelationIsPopulated(matviewRel))
172+
continue;
173+
170174
/*
171175
* AQUMV
172176
* Currently the data of IVM is always up-to-date if there were.
173-
* Take care of this when IVM defered-fefresh is supported.
177+
* Take care of this when IVM defered-fefresh is supported(in SERVERLESS mode).
178+
*
179+
* Normal materialized views could also be used if its data is up to date.
174180
*/
175-
if (!(RelationIsIVM(matviewRel) && RelationIsPopulated(matviewRel)))
181+
if (!RelationIsIVM(matviewRel) &&
182+
!MatviewIsGeneralyUpToDate(RelationGetRelid(matviewRel)))
176183
continue;
177184

178185
if (matviewRel->rd_rel->relhasrules == false ||

src/test/regress/expected/aqumv.out

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,118 @@ select count(c2), count(*) from aqumv_t2 where c1 > 90;
988988
(1 row)
989989

990990
abort;
991+
-- Test use normal materialized views
992+
create table t1(c1 int, c2 int, c3 int) distributed by (c1);
993+
insert into t1 select i, i+1, i+2 from generate_series(1, 100) i;
994+
insert into t1 values (91, NULL, 95);
995+
analyze t1;
996+
create materialized view normal_mv_t1 as
997+
select c3 as mc3, c1 as mc1
998+
from t1 where c1 > 90;
999+
NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column(s) named 'mc1' as the Cloudberry Database data distribution key for this table.
1000+
HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew.
1001+
analyze normal_mv_t1;
1002+
set enable_answer_query_using_materialized_views = off;
1003+
explain(costs off, verbose)
1004+
select count(c3) from t1 where c1 > 90;
1005+
QUERY PLAN
1006+
-----------------------------------------------------------------------------------
1007+
Finalize Aggregate
1008+
Output: count(c3)
1009+
-> Gather Motion 3:1 (slice1; segments: 3)
1010+
Output: (PARTIAL count(c3))
1011+
-> Partial Aggregate
1012+
Output: PARTIAL count(c3)
1013+
-> Seq Scan on aqumv.t1
1014+
Output: c1, c2, c3
1015+
Filter: (t1.c1 > 90)
1016+
Settings: enable_answer_query_using_materialized_views = 'off', optimizer = 'off'
1017+
Optimizer: Postgres query optimizer
1018+
(11 rows)
1019+
1020+
select count(c3) from t1 where c1 > 90;
1021+
count
1022+
-------
1023+
11
1024+
(1 row)
1025+
1026+
set enable_answer_query_using_materialized_views = on;
1027+
explain(costs off, verbose)
1028+
select count(c3) from t1 where c1 > 90;
1029+
QUERY PLAN
1030+
----------------------------------------------------------------------------------
1031+
Finalize Aggregate
1032+
Output: count(mc3)
1033+
-> Gather Motion 3:1 (slice1; segments: 3)
1034+
Output: (PARTIAL count(mc3))
1035+
-> Partial Aggregate
1036+
Output: PARTIAL count(mc3)
1037+
-> Seq Scan on aqumv.normal_mv_t1
1038+
Output: mc3, mc1
1039+
Settings: enable_answer_query_using_materialized_views = 'on', optimizer = 'off'
1040+
Optimizer: Postgres query optimizer
1041+
(10 rows)
1042+
1043+
select count(c3) from t1 where c1 > 90;
1044+
count
1045+
-------
1046+
11
1047+
(1 row)
1048+
1049+
vacuum full t1;
1050+
explain(costs off, verbose)
1051+
select count(c3) from t1 where c1 > 90;
1052+
QUERY PLAN
1053+
----------------------------------------------------------------------------------
1054+
Finalize Aggregate
1055+
Output: count(mc3)
1056+
-> Gather Motion 3:1 (slice1; segments: 3)
1057+
Output: (PARTIAL count(mc3))
1058+
-> Partial Aggregate
1059+
Output: PARTIAL count(mc3)
1060+
-> Seq Scan on aqumv.normal_mv_t1
1061+
Output: mc3, mc1
1062+
Settings: enable_answer_query_using_materialized_views = 'on', optimizer = 'off'
1063+
Optimizer: Postgres query optimizer
1064+
(10 rows)
1065+
1066+
explain(costs off, verbose)
1067+
select c3 from t1 where c1 > 90;
1068+
QUERY PLAN
1069+
----------------------------------------------------------------------------------
1070+
Gather Motion 3:1 (slice1; segments: 3)
1071+
Output: mc3
1072+
-> Seq Scan on aqumv.normal_mv_t1
1073+
Output: mc3
1074+
Settings: enable_answer_query_using_materialized_views = 'on', optimizer = 'off'
1075+
Optimizer: Postgres query optimizer
1076+
(6 rows)
1077+
1078+
-- insert data after refresh
1079+
insert into t1 values (91, NULL, 95);
1080+
explain(costs off, verbose)
1081+
select count(c3) from t1 where c1 > 90;
1082+
QUERY PLAN
1083+
----------------------------------------------------------------------------------
1084+
Finalize Aggregate
1085+
Output: count(c3)
1086+
-> Gather Motion 3:1 (slice1; segments: 3)
1087+
Output: (PARTIAL count(c3))
1088+
-> Partial Aggregate
1089+
Output: PARTIAL count(c3)
1090+
-> Seq Scan on aqumv.t1
1091+
Output: c1, c2, c3
1092+
Filter: (t1.c1 > 90)
1093+
Settings: enable_answer_query_using_materialized_views = 'on', optimizer = 'off'
1094+
Optimizer: Postgres query optimizer
1095+
(11 rows)
1096+
1097+
select mvname, datastatus from gp_matview_aux where mvname = 'normal_mv_t1';
1098+
mvname | datastatus
1099+
--------------+------------
1100+
normal_mv_t1 | e
1101+
(1 row)
1102+
9911103
-- Test Agg on IMMV who has less columns than origin table.
9921104
begin;
9931105
create table aqumv_t2(c1 int, c2 int, c3 int) distributed by (c1);
@@ -2471,5 +2583,7 @@ select c2, c3 from aqumv_t7 where c1 > 90 order by c2, c3 fetch first 3 rows wit
24712583
abort;
24722584
reset optimizer;
24732585
reset enable_answer_query_using_materialized_views;
2474-
drop table aqumv_t1 cascade;
2586+
-- start_ignore
2587+
drop schema aqumv cascade;
2588+
-- end_ignore
24752589
reset search_path;

src/test/regress/sql/aqumv.sql

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,39 @@ select count(c2), count(*) from aqumv_t2 where c1 > 90;
291291
select count(c2), count(*) from aqumv_t2 where c1 > 90;
292292
abort;
293293

294+
-- Test use normal materialized views
295+
create table t1(c1 int, c2 int, c3 int) distributed by (c1);
296+
insert into t1 select i, i+1, i+2 from generate_series(1, 100) i;
297+
insert into t1 values (91, NULL, 95);
298+
analyze t1;
299+
300+
create materialized view normal_mv_t1 as
301+
select c3 as mc3, c1 as mc1
302+
from t1 where c1 > 90;
303+
analyze normal_mv_t1;
304+
305+
set enable_answer_query_using_materialized_views = off;
306+
explain(costs off, verbose)
307+
select count(c3) from t1 where c1 > 90;
308+
select count(c3) from t1 where c1 > 90;
309+
set enable_answer_query_using_materialized_views = on;
310+
explain(costs off, verbose)
311+
select count(c3) from t1 where c1 > 90;
312+
select count(c3) from t1 where c1 > 90;
313+
314+
vacuum full t1;
315+
explain(costs off, verbose)
316+
select count(c3) from t1 where c1 > 90;
317+
318+
explain(costs off, verbose)
319+
select c3 from t1 where c1 > 90;
320+
321+
-- insert data after refresh
322+
insert into t1 values (91, NULL, 95);
323+
explain(costs off, verbose)
324+
select count(c3) from t1 where c1 > 90;
325+
select mvname, datastatus from gp_matview_aux where mvname = 'normal_mv_t1';
326+
294327
-- Test Agg on IMMV who has less columns than origin table.
295328
begin;
296329
create table aqumv_t2(c1 int, c2 int, c3 int) distributed by (c1);
@@ -595,5 +628,7 @@ abort;
595628

596629
reset optimizer;
597630
reset enable_answer_query_using_materialized_views;
598-
drop table aqumv_t1 cascade;
631+
-- start_ignore
632+
drop schema aqumv cascade;
633+
-- end_ignore
599634
reset search_path;

0 commit comments

Comments
 (0)