--------------------------------------------------------------------- --- 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 router materialized views CREATE MATERIALIZED VIEW mode_counts_router AS SELECT l_shipmode, count(*) FROM temp_lineitem WHERE l_orderkey = 1 GROUP BY l_shipmode; SELECT * FROM mode_counts_router; l_shipmode | count --------------------------------------------------------------------- AIR | 1 (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); count --------------------------------------------------------------------- 1706 (1 row) -- 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; NOTICE: drop cascades to materialized view mode_counts_router -- 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... NOTICE: copying the data has completed DETAIL: The local data in the table is no longer visible, but is still on disk. HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$materialized_view.lineitem_local_to_hash_part$$) create_distributed_table --------------------------------------------------------------------- (1 row) SELECT create_distributed_table('orders_local_to_hash_part', 'o_orderkey'); NOTICE: Copying data from local table... NOTICE: copying the data has completed DETAIL: The local data in the table is no longer visible, but is still on disk. HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$materialized_view.orders_local_to_hash_part$$) 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; SELECT * FROM large ORDER BY 1, 2; id | tenant_id --------------------------------------------------------------------- 2 | 3 5 | 4 20 | 2 20 | 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; SELECT * FROM large ORDER BY 1, 2; id | tenant_id --------------------------------------------------------------------- 2 | 3 5 | 4 20 | 2 20 | 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 --------------------------------------------------------------------- 20 | 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; SELECT * FROM large_partitioned ORDER BY 1, 2; id | tenant_id --------------------------------------------------------------------- 2 | 3 5 | 4 20 | 2 20 | 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 20 | 2 20 | 5 26 | 32 29 | 15 60 | 51 (7 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) CREATE MATERIALIZED VIEW only_intermedate_result AS WITH cte_1 AS (SELECT * FROM small OFFSET 0) SELECT * FROM cte_1 ORDER BY 1,2; SELECT * FROM only_intermedate_result ORDER BY 1,2; id | tenant_id --------------------------------------------------------------------- 1 | 2 6 | 3 7 | 4 8 | 2 14 | 14 250 | 25 470 | 13 (7 rows) INSERT INTO small VALUES (1000000,1000000); REFRESH MATERIALIZED VIEW only_intermedate_result; SELECT * FROM only_intermedate_result ORDER BY 1,2; id | tenant_id --------------------------------------------------------------------- 1 | 2 6 | 3 7 | 4 8 | 2 14 | 14 250 | 25 470 | 13 1000000 | 1000000 (8 rows) DROP TABLE large_partitioned; DROP TABLE small CASCADE; NOTICE: drop cascades to 2 other objects DETAIL: drop cascades to materialized view small_view drop cascades to materialized view only_intermedate_result