timescaledb/test/sql/partitionwise.sql.in
Ante Kresic c81ae6ff50 Use processed group clauses in PG16
Latest version of Postgres introduced an optimization
which removes redundant grouping and DISTINCT columns.
This optimization needs to be taken into account when
generating pushdown aggregation plans so we can create
valid plans with correct grouping columns.
2023-12-05 16:15:24 +01:00

285 lines
7.7 KiB
MySQL

-- This file and its contents are licensed under the Apache License 2.0.
-- Please see the included NOTICE for copyright information and
-- LICENSE-APACHE for a copy of the license.
\set PREFIX 'EXPLAIN (VERBOSE, COSTS OFF)'
-- Create a two dimensional hypertable
CREATE TABLE hyper (time timestamptz, device int, temp float);
SELECT * FROM create_hypertable('hyper', 'time', 'device', 2);
-- Create a similar PostgreSQL partitioned table
CREATE TABLE pg2dim (time timestamptz, device int, temp float) PARTITION BY HASH (device);
CREATE TABLE pg2dim_h1 PARTITION OF pg2dim FOR VALUES WITH (MODULUS 2, REMAINDER 0) PARTITION BY RANGE(time);
CREATE TABLE pg2dim_h2 PARTITION OF pg2dim FOR VALUES WITH (MODULUS 2, REMAINDER 1) PARTITION BY RANGE(time);
CREATE TABLE pg2dim_h1_t1 PARTITION OF pg2dim_h1 FOR VALUES FROM ('2018-01-01 00:00') TO ('2018-09-01 00:00');
CREATE TABLE pg2dim_h1_t2 PARTITION OF pg2dim_h1 FOR VALUES FROM ('2018-09-01 00:00') TO ('2018-12-01 00:00');
CREATE TABLE pg2dim_h2_t1 PARTITION OF pg2dim_h2 FOR VALUES FROM ('2018-01-01 00:00') TO ('2018-09-01 00:00');
CREATE TABLE pg2dim_h2_t2 PARTITION OF pg2dim_h2 FOR VALUES FROM ('2018-09-01 00:00') TO ('2018-12-01 00:00');
-- Create a 1-dimensional partitioned table for comparison
CREATE TABLE pg1dim (time timestamptz, device int, temp float) PARTITION BY HASH (device);
CREATE TABLE pg1dim_h1 PARTITION OF pg1dim FOR VALUES WITH (MODULUS 2, REMAINDER 0);
CREATE TABLE pg1dim_h2 PARTITION OF pg1dim FOR VALUES WITH (MODULUS 2, REMAINDER 1);
INSERT INTO hyper VALUES
('2018-02-19 13:01', 1, 2.3),
('2018-02-19 13:02', 3, 3.1),
('2018-10-19 13:01', 1, 7.6),
('2018-10-19 13:02', 3, 9.0);
INSERT INTO pg2dim VALUES
('2018-02-19 13:01', 1, 2.3),
('2018-02-19 13:02', 3, 3.1),
('2018-10-19 13:01', 1, 7.6),
('2018-10-19 13:02', 3, 9.0);
INSERT INTO pg1dim VALUES
('2018-02-19 13:01', 1, 2.3),
('2018-02-19 13:02', 3, 3.1),
('2018-10-19 13:01', 1, 7.6),
('2018-10-19 13:02', 3, 9.0);
SELECT * FROM test.show_subtables('hyper');
SELECT * FROM pg2dim_h1_t1;
SELECT * FROM pg2dim_h1_t2;
SELECT * FROM pg2dim_h2_t1;
SELECT * FROM pg2dim_h2_t2;
-- Compare partitionwise aggreate enabled/disabled. First run queries
-- on PG partitioned tables for reference.
-- All partition keys covered by GROUP BY
SET enable_partitionwise_aggregate = 'off';
:PREFIX
SELECT device, avg(temp)
FROM pg1dim
GROUP BY 1
ORDER BY 1;
SET enable_partitionwise_aggregate = 'on';
:PREFIX
SELECT device, avg(temp)
FROM pg1dim
GROUP BY 1
ORDER BY 1;
-- All partition keys not covered by GROUP BY (partial partitionwise)
SET enable_partitionwise_aggregate = 'off';
:PREFIX
SELECT device, avg(temp)
FROM pg2dim
GROUP BY 1
ORDER BY 1;
SET enable_partitionwise_aggregate = 'on';
:PREFIX
SELECT device, avg(temp)
FROM pg2dim
GROUP BY 1
ORDER BY 1;
-- All partition keys covered by GROUP BY (full partitionwise)
SET enable_partitionwise_aggregate = 'off';
:PREFIX
SELECT time, device, avg(temp)
FROM pg2dim
GROUP BY 1, 2
ORDER BY 1, 2;
SET enable_partitionwise_aggregate = 'on';
:PREFIX
SELECT time, device, avg(temp)
FROM pg2dim
GROUP BY 1, 2
ORDER BY 1, 2;
-- All partition keys not covered by GROUP BY because of date_trunc
-- expression on time (partial partitionwise)
SET enable_partitionwise_aggregate = 'off';
:PREFIX
SELECT date_trunc('month', time), device, avg(temp)
FROM pg2dim
GROUP BY 1, 2
ORDER BY 1, 2;
SET enable_partitionwise_aggregate = 'on';
:PREFIX
SELECT date_trunc('month', time), device, avg(temp)
FROM pg2dim
GROUP BY 1, 2
ORDER BY 1, 2;
-- Now run on hypertable
-- All partition keys not covered by GROUP BY (partial partitionwise)
SET timescaledb.enable_chunkwise_aggregation = 'off';
:PREFIX
SELECT device, avg(temp)
FROM hyper
GROUP BY 1
ORDER BY 1;
SET timescaledb.enable_chunkwise_aggregation = 'on';
:PREFIX
SELECT device, avg(temp)
FROM hyper
GROUP BY 1
ORDER BY 1;
-- All partition keys covered (full partitionwise)
SET timescaledb.enable_chunkwise_aggregation = 'off';
:PREFIX
SELECT time, device, avg(temp)
FROM hyper
GROUP BY 1, 2
ORDER BY 1, 2;
SET timescaledb.enable_chunkwise_aggregation = 'on';
:PREFIX
SELECT time, device, avg(temp)
FROM hyper
GROUP BY 1, 2
ORDER BY 1, 2;
-- Partial aggregation since date_trunc(time) is not a partition key
SET enable_partitionwise_aggregate = 'off';
:PREFIX
SELECT date_trunc('month', time), device, avg(temp)
FROM hyper
GROUP BY 1, 2
ORDER BY 1, 2;
-- Partial aggregation pushdown is currently not supported for this query by
-- the TSDB pushdown code since a projection is used in the path.
SET enable_partitionwise_aggregate = 'on';
:PREFIX
SELECT date_trunc('month', time), device, avg(temp)
FROM hyper
GROUP BY 1, 2
ORDER BY 1, 2;
-- Also test time_bucket
SET timescaledb.enable_chunkwise_aggregation = 'off';
:PREFIX
SELECT time_bucket('1 month', time), device, avg(temp)
FROM hyper
GROUP BY 1, 2
ORDER BY 1, 2;
SET timescaledb.enable_chunkwise_aggregation = 'on';
:PREFIX
SELECT time_bucket('1 month', time), device, avg(temp)
FROM hyper
GROUP BY 1, 2
ORDER BY 1, 2;
-- Test partitionwise joins, mostly to see that we do not break
-- anything
CREATE TABLE hyper_meta (time timestamptz, device int, info text);
SELECT * FROM create_hypertable('hyper_meta', 'time', 'device', 2);
INSERT INTO hyper_meta VALUES
('2018-02-19 13:01', 1, 'device_1'),
('2018-02-19 13:02', 3, 'device_3');
SET enable_partitionwise_join = 'off';
:PREFIX
SELECT h.time, h.device, h.temp, hm.info
FROM hyper h, hyper_meta hm
WHERE h.device = hm.device;
:PREFIX
SELECT pg2.time, pg2.device, pg2.temp, pg1.temp
FROM pg2dim pg2, pg1dim pg1
WHERE pg2.device = pg1.device;
SET enable_partitionwise_join = 'on';
:PREFIX
SELECT h.time, h.device, h.temp, hm.info
FROM hyper h, hyper_meta hm
WHERE h.device = hm.device;
:PREFIX
SELECT pg2.time, pg2.device, pg2.temp, pg1.temp
FROM pg2dim pg2, pg1dim pg1
WHERE pg2.device = pg1.device;
-- Test hypertable with time partitioning function
CREATE OR REPLACE FUNCTION time_func(unixtime float8)
RETURNS TIMESTAMPTZ LANGUAGE PLPGSQL IMMUTABLE AS
$BODY$
DECLARE
retval TIMESTAMPTZ;
BEGIN
retval := to_timestamp(unixtime);
RETURN retval;
END
$BODY$;
CREATE TABLE hyper_timepart (time float8, device int, temp float);
SELECT * FROM create_hypertable('hyper_timepart', 'time', 'device', 2, time_partitioning_func => 'time_func');
-- Planner won't pick push-down aggs on table with time function
-- unless a certain amount of data
SELECT setseed(1);
INSERT INTO hyper_timepart
SELECT x, ceil(random() * 8), random() * 20
FROM generate_series(0,5000-1) AS x;
-- All partition keys covered (full partitionwise)
SET timescaledb.enable_chunkwise_aggregation = 'off';
:PREFIX
SELECT time, device, avg(temp)
FROM hyper_timepart
GROUP BY 1, 2
ORDER BY 1, 2
LIMIT 10;
:PREFIX
SELECT time_func(time), device, avg(temp)
FROM hyper_timepart
GROUP BY 1, 2
ORDER BY 1, 2
LIMIT 10;
-- Grouping on original time column should be pushed-down
SET timescaledb.enable_chunkwise_aggregation = 'on';
:PREFIX
SELECT time, device, avg(temp)
FROM hyper_timepart
GROUP BY 1, 2
ORDER BY 1, 2
LIMIT 10;
-- Applying the time partitioning function should also allow push-down
-- on open dimensions
:PREFIX
SELECT time_func(time), device, avg(temp)
FROM hyper_timepart
GROUP BY 1, 2
ORDER BY 1, 2
LIMIT 10;
-- Partial aggregation pushdown is currently not supported for this query by
-- the TSDB pushdown code since a projection is used in the path.
:PREFIX
SELECT time_func(time), _timescaledb_functions.get_partition_hash(device), avg(temp)
FROM hyper_timepart
GROUP BY 1, 2
ORDER BY 1, 2
LIMIT 10;
-- Test removal of redundant group key optimization in PG16
-- All lower versions include the redundant key on device column
:PREFIX
SELECT device, avg(temp)
FROM hyper_timepart
WHERE device = 1
GROUP BY 1
LIMIT 10;