--- --- materialized_view --- -- This file contains test cases for materialized view support. -- materialized views work -- insert into... select works with views CREATE SCHEMA materialized_view; SET search_path TO materialized_view, public; CREATE VIEW air_shipped_lineitems AS SELECT * FROM lineitem_hash_part WHERE l_shipmode = 'AIR'; CREATE TABLE temp_lineitem(LIKE lineitem_hash_part); SELECT create_distributed_table('temp_lineitem', 'l_orderkey', 'hash', 'lineitem_hash_part'); create_distributed_table -------------------------- (1 row) INSERT INTO temp_lineitem SELECT * FROM air_shipped_lineitems; SELECT count(*) FROM temp_lineitem; count ------- 1706 (1 row) -- following is a where false query, should not be inserting anything INSERT INTO temp_lineitem SELECT * FROM air_shipped_lineitems WHERE l_shipmode = 'MAIL'; SELECT count(*) FROM temp_lineitem; count ------- 1706 (1 row) -- can create and query materialized views CREATE MATERIALIZED VIEW mode_counts AS SELECT l_shipmode, count(*) FROM temp_lineitem GROUP BY l_shipmode; SELECT * FROM mode_counts WHERE l_shipmode = 'AIR' ORDER BY 2 DESC, 1 LIMIT 10; l_shipmode | count ------------+------- AIR | 1706 (1 row) -- materialized views are local, cannot join with distributed tables SELECT count(*) FROM mode_counts JOIN temp_lineitem USING (l_shipmode); ERROR: relation mode_counts is not distributed -- new data is not immediately reflected in the view INSERT INTO temp_lineitem SELECT * FROM air_shipped_lineitems; SELECT * FROM mode_counts WHERE l_shipmode = 'AIR' ORDER BY 2 DESC, 1 LIMIT 10; l_shipmode | count ------------+------- AIR | 1706 (1 row) -- refresh updates the materialised view with new data REFRESH MATERIALIZED VIEW mode_counts; SELECT * FROM mode_counts WHERE l_shipmode = 'AIR' ORDER BY 2 DESC, 1 LIMIT 10; l_shipmode | count ------------+------- AIR | 3412 (1 row) DROP MATERIALIZED VIEW mode_counts; DROP TABLE temp_lineitem CASCADE; -- Refresh single-shard materialized view CREATE MATERIALIZED VIEW materialized_view AS SELECT orders_hash_part.o_orderdate, total_price.price_sum FROM lineitem_hash_part, orders_hash_part, (SELECT SUM(l_extendedprice) AS price_sum FROM lineitem_hash_part where l_orderkey=3) AS total_price WHERE lineitem_hash_part.l_orderkey=orders_hash_part.o_orderkey AND lineitem_hash_part.l_orderkey=3; REFRESH MATERIALIZED VIEW materialized_view; SELECT count(*) FROM materialized_view; count ------- 6 (1 row) DROP MATERIALIZED VIEW materialized_view; -- Refresh multi-shard materialized view CREATE MATERIALIZED VIEW materialized_view AS SELECT orders_hash_part.o_orderdate, total_price.price_sum FROM lineitem_hash_part, orders_hash_part, (SELECT SUM(l_extendedprice) AS price_sum FROM lineitem_hash_part) AS total_price WHERE lineitem_hash_part.l_orderkey=orders_hash_part.o_orderkey; REFRESH MATERIALIZED VIEW materialized_view; SELECT count(*) FROM materialized_view; count ------- 12000 (1 row) DROP MATERIALIZED VIEW materialized_view; -- Refresh materialized view with CTE CREATE MATERIALIZED VIEW materialized_view AS WITH total_price AS (SELECT SUM(l_extendedprice) AS price_sum FROM lineitem_hash_part) SELECT orders_hash_part.o_orderdate, total_price.price_sum FROM lineitem_hash_part, orders_hash_part, total_price WHERE lineitem_hash_part.l_orderkey=orders_hash_part.o_orderkey; REFRESH MATERIALIZED VIEW materialized_view; SELECT count(*) FROM materialized_view; count ------- 12000 (1 row) DROP MATERIALIZED VIEW materialized_view; -- Refresh materialized view with join CREATE MATERIALIZED VIEW materialized_view AS SELECT orders_hash_part.o_orderdate, quantity_sum FROM orders_hash_part JOIN ( SELECT l_orderkey, SUM(l_quantity) AS quantity_sum FROM lineitem_hash_part GROUP BY l_orderkey ) AS total_quantity ON total_quantity.l_orderkey=orders_hash_part.o_orderkey; REFRESH MATERIALIZED VIEW materialized_view; SELECT count(*) FROM materialized_view; count ------- 2985 (1 row) DROP MATERIALIZED VIEW materialized_view; -- Refresh materialized view with reference tables CREATE MATERIALIZED VIEW materialized_view AS SELECT orders_reference.o_orderdate, total_price.price_sum FROM lineitem_hash_part, orders_reference, (SELECT SUM(o_totalprice) AS price_sum FROM orders_reference) AS total_price WHERE lineitem_hash_part.l_orderkey=orders_reference.o_orderkey; REFRESH MATERIALIZED VIEW materialized_view; SELECT count(*) FROM materialized_view; count ------- 12000 (1 row) DROP MATERIALIZED VIEW materialized_view; -- Refresh materialized view with table distributed after creation of view CREATE TABLE lineitem_local_to_hash_part AS SELECT * FROM lineitem_hash_part; CREATE TABLE orders_local_to_hash_part AS SELECT * FROM orders_hash_part; CREATE MATERIALIZED VIEW materialized_view AS SELECT orders_local_to_hash_part.o_orderdate, total_price.price_sum FROM lineitem_local_to_hash_part, orders_local_to_hash_part, (SELECT SUM(l_extendedprice) AS price_sum FROM lineitem_local_to_hash_part) AS total_price WHERE lineitem_local_to_hash_part.l_orderkey=orders_local_to_hash_part.o_orderkey; SELECT create_distributed_table('lineitem_local_to_hash_part', 'l_orderkey'); NOTICE: Copying data from local table... create_distributed_table -------------------------- (1 row) SELECT create_distributed_table('orders_local_to_hash_part', 'o_orderkey'); NOTICE: Copying data from local table... create_distributed_table -------------------------- (1 row) REFRESH MATERIALIZED VIEW materialized_view; SELECT count(*) FROM materialized_view; count ------- 12000 (1 row) DROP MATERIALIZED VIEW materialized_view; DROP TABLE lineitem_local_to_hash_part; DROP TABLE orders_local_to_hash_part; -- Refresh materialized view WITH DATA CREATE MATERIALIZED VIEW materialized_view AS SELECT orders_hash_part.o_orderdate, total_price.price_sum FROM lineitem_hash_part, orders_hash_part, (SELECT SUM(l_extendedprice) AS price_sum FROM lineitem_hash_part) AS total_price WHERE lineitem_hash_part.l_orderkey=orders_hash_part.o_orderkey; REFRESH MATERIALIZED VIEW materialized_view WITH DATA; SELECT count(*) FROM materialized_view; count ------- 12000 (1 row) DROP MATERIALIZED VIEW materialized_view; -- Refresh materialized view WITH NO DATA CREATE MATERIALIZED VIEW materialized_view AS SELECT orders_hash_part.o_orderdate, total_price.price_sum FROM lineitem_hash_part, orders_hash_part, (SELECT SUM(l_extendedprice) AS price_sum FROM lineitem_hash_part) AS total_price WHERE lineitem_hash_part.l_orderkey=orders_hash_part.o_orderkey; REFRESH MATERIALIZED VIEW materialized_view WITH NO DATA; SELECT count(*) FROM materialized_view; ERROR: materialized view "materialized_view" has not been populated HINT: Use the REFRESH MATERIALIZED VIEW command. DROP MATERIALIZED VIEW materialized_view; -- Refresh materialized view CONCURRENTLY CREATE MATERIALIZED VIEW materialized_view AS SELECT orders_hash_part.o_orderdate, SUM(total_price.price_sum) FROM lineitem_hash_part, orders_hash_part, (SELECT SUM(l_extendedprice) AS price_sum FROM lineitem_hash_part) AS total_price WHERE lineitem_hash_part.l_orderkey=orders_hash_part.o_orderkey GROUP BY orders_hash_part.o_orderdate; CREATE UNIQUE INDEX materialized_view_index ON materialized_view (o_orderdate); REFRESH MATERIALIZED VIEW CONCURRENTLY materialized_view; SELECT count(*) FROM materialized_view; count ------- 1699 (1 row) DROP MATERIALIZED VIEW materialized_view; DROP SCHEMA materialized_view CASCADE; NOTICE: drop cascades to view air_shipped_lineitems -- modify statements on/with views -- create two tables and a view CREATE TABLE large (id int, tenant_id int); CREATE TABLE small (id int, tenant_id int); SELECT create_distributed_table('large','tenant_id'); create_distributed_table -------------------------- (1 row) SELECT create_distributed_table('small','tenant_id'); create_distributed_table -------------------------- (1 row) \copy small FROM STDIN DELIMITER ',' CREATE MATERIALIZED VIEW small_view AS SELECT * from small where id < 100; \copy large FROM STDIN DELIMITER ',' -- running any kind of modify statements "on" materialized views is not supported by postgres UPDATE small_view SET id = 1; ERROR: cannot change materialized view "small_view" -- for now, using materialized views in modify statements' FROM / WHERE clauses is not supported UPDATE large SET id=20 FROM small_view WHERE small_view.id=large.id; ERROR: materialized views in modify queries are not supported SELECT * FROM large ORDER BY 1, 2; id | tenant_id ----+----------- 1 | 2 2 | 3 5 | 4 6 | 5 (4 rows) -- test on a router executable update statement, this will also fail UPDATE large SET id=28 FROM small_view WHERE small_view.id=large.id and small_view.tenant_id=2 and large.tenant_id=2; ERROR: materialized views in modify queries are not supported SELECT * FROM large ORDER BY 1, 2; id | tenant_id ----+----------- 1 | 2 2 | 3 5 | 4 6 | 5 (4 rows) -- delete statement on large with subquery, this should succeed DELETE FROM large WHERE tenant_id in (SELECT tenant_id FROM small_view); SELECT * FROM large ORDER BY 1, 2; id | tenant_id ----+----------- 6 | 5 (1 row) -- INSERT INTO views is already not supported by PostgreSQL INSERT INTO small_view VALUES(3, 3); ERROR: cannot change materialized view "small_view" DROP TABLE small CASCADE; NOTICE: drop cascades to materialized view small_view DROP TABLE large; -- now, run the same modify statement tests on a partitioned table CREATE TABLE small (id int, tenant_id int); CREATE TABLE large_partitioned (id int, tenant_id int) partition by range(tenant_id); CREATE TABLE large_partitioned_p1 PARTITION OF large_partitioned FOR VALUES FROM (1) TO (10); CREATE TABLE large_partitioned_p2 PARTITION OF large_partitioned FOR VALUES FROM (10) TO (20); CREATE TABLE large_partitioned_p3 PARTITION OF large_partitioned FOR VALUES FROM (20) TO (100); SELECT create_distributed_table('large_partitioned','tenant_id'); create_distributed_table -------------------------- (1 row) SELECT create_distributed_table('small','tenant_id'); create_distributed_table -------------------------- (1 row) \copy small FROM STDIN DELIMITER ',' CREATE MATERIALIZED VIEW small_view AS SELECT * from small where id < 100; \copy large_partitioned FROM STDIN DELIMITER ',' -- running modify statements "on" views is still not supported, hence below two statements will fail UPDATE small_view SET id = 1; ERROR: cannot change materialized view "small_view" DELETE FROM small_view; ERROR: cannot change materialized view "small_view" -- using mat. view in modify statements' FROM / WHERE clauses is not valid yet UPDATE large_partitioned SET id=20 FROM small_view WHERE small_view.id=large_partitioned.id; ERROR: materialized views in modify queries are not supported SELECT * FROM large_partitioned ORDER BY 1, 2; id | tenant_id ----+----------- 1 | 2 2 | 3 5 | 4 6 | 5 26 | 32 29 | 15 60 | 51 (7 rows) -- delete statement on large_partitioned DELETE FROM large_partitioned WHERE id in (SELECT id FROM small_view); SELECT * FROM large_partitioned ORDER BY 1, 2; id | tenant_id ----+----------- 2 | 3 5 | 4 26 | 32 29 | 15 60 | 51 (5 rows) -- we should still have identical rows for next test statement, then insert new rows to both tables INSERT INTO large_partitioned VALUES(14, 14); INSERT INTO small VALUES(14, 14); -- delete statement with CTE WITH all_small_view_ids AS (SELECT id FROM small_view) DELETE FROM large_partitioned WHERE id in (SELECT * FROM all_small_view_ids); -- make sure that materialized view in a CTE/subquery can be joined with a distributed table WITH cte AS (SELECT *, random() FROM small_view) SELECT count(*) FROM cte JOIN small USING(id); count ------- 4 (1 row) SELECT count(*) FROM (SELECT *, random() FROM small_view) as subquery JOIN small USING(id); count ------- 4 (1 row) DROP TABLE large_partitioned; DROP TABLE small CASCADE; NOTICE: drop cascades to materialized view small_view