mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-15 18:13:18 +08:00
PG16 renamed force_parallel_mode to debug_parallel_query. https://github.com/postgres/postgres/commit/5352ca22e
186 lines
8.2 KiB
MySQL
186 lines
8.2 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.
|
|
|
|
--parallel queries require big-ish tables so collect them all here
|
|
--so that we need to generate queries only once.
|
|
|
|
-- output with analyze is not stable because it depends on worker assignment
|
|
\set PREFIX 'EXPLAIN (costs off)'
|
|
|
|
\set CHUNK1 _timescaledb_internal._hyper_1_1_chunk
|
|
\set CHUNK2 _timescaledb_internal._hyper_1_2_chunk
|
|
|
|
CREATE TABLE test (i int, j double precision, ts timestamp);
|
|
SELECT create_hypertable('test','i',chunk_time_interval:=500000);
|
|
INSERT INTO test SELECT x, x+0.1, _timescaledb_functions.to_timestamp(x*1000) FROM generate_series(0,1000000-1,10) AS x;
|
|
|
|
ANALYZE test;
|
|
ALTER TABLE :CHUNK1 SET (parallel_workers=2);
|
|
ALTER TABLE :CHUNK2 SET (parallel_workers=2);
|
|
|
|
SET work_mem TO '50MB';
|
|
SELECT set_config(CASE WHEN current_setting('server_version_num')::int < 160000 THEN 'force_parallel_mode' ELSE 'debug_parallel_query' END,'on', false);
|
|
SET max_parallel_workers_per_gather = 4;
|
|
SET parallel_setup_cost TO 0;
|
|
|
|
EXPLAIN (costs off) SELECT first(i, j) FROM "test";
|
|
SELECT first(i, j) FROM "test";
|
|
|
|
EXPLAIN (costs off) SELECT last(i, j) FROM "test";
|
|
SELECT last(i, j) FROM "test";
|
|
|
|
EXPLAIN (costs off) SELECT time_bucket('1 second', ts) sec, last(i, j)
|
|
FROM "test"
|
|
GROUP BY sec
|
|
ORDER BY sec
|
|
LIMIT 5;
|
|
|
|
-- test single copy parallel plan with parallel chunk append
|
|
:PREFIX SELECT time_bucket('1 second', ts) sec, last(i, j)
|
|
FROM "test"
|
|
WHERE length(version()) > 0
|
|
GROUP BY sec
|
|
ORDER BY sec
|
|
LIMIT 5;
|
|
|
|
SELECT time_bucket('1 second', ts) sec, last(i, j)
|
|
FROM "test"
|
|
GROUP BY sec
|
|
ORDER BY sec
|
|
LIMIT 5;
|
|
|
|
--test variants of histogram
|
|
EXPLAIN (costs off) SELECT histogram(i, 1, 1000000, 2) FROM "test";
|
|
SELECT histogram(i, 1, 1000000, 2) FROM "test";
|
|
|
|
EXPLAIN (costs off) SELECT histogram(i, 1,1000001,10) FROM "test";
|
|
SELECT histogram(i, 1, 1000001, 10) FROM "test";
|
|
|
|
EXPLAIN (costs off) SELECT histogram(i, 0,100000,5) FROM "test";
|
|
SELECT histogram(i, 0, 100000, 5) FROM "test";
|
|
|
|
EXPLAIN (costs off) SELECT histogram(i, 10,100000,5) FROM "test";
|
|
SELECT histogram(i, 10, 100000, 5) FROM "test";
|
|
|
|
EXPLAIN (costs off) SELECT histogram(NULL, 10,100000,5) FROM "test" WHERE i = coalesce(-1,j);
|
|
SELECT histogram(NULL, 10,100000,5) FROM "test" WHERE i = coalesce(-1,j);
|
|
|
|
-- test parallel ChunkAppend
|
|
:PREFIX SELECT i FROM "test" WHERE length(version()) > 0;
|
|
|
|
:PREFIX SELECT count(*) FROM "test" WHERE i > 1 AND length(version()) > 0;
|
|
SELECT count(*) FROM "test" WHERE i > 1 AND length(version()) > 0;
|
|
|
|
-- test parallel ChunkAppend with only work done in the parallel workers
|
|
SET parallel_leader_participation = off;
|
|
SELECT count(*) FROM "test" WHERE i > 1 AND length(version()) > 0;
|
|
RESET parallel_leader_participation;
|
|
|
|
-- Test parallel chunk append is used
|
|
SET parallel_tuple_cost = 0;
|
|
:PREFIX SELECT * FROM (SELECT * FROM "test" WHERE length(version()) > 0 LIMIT 10) AS t1 LEFT JOIN (SELECT * FROM "test" WHERE i < 500000 LIMIT 10) AS t2 ON (t1.i = t2.i) ORDER BY t1.i, t2.i;
|
|
SELECT * FROM (SELECT * FROM "test" WHERE length(version()) > 0 LIMIT 10) AS t1 LEFT JOIN (SELECT * FROM "test" WHERE i < 500000 LIMIT 10) AS t2 ON (t1.i = t2.i) ORDER BY t1.i, t2.i;
|
|
|
|
-- Test normal chunk append can be used in a parallel worker
|
|
:PREFIX SELECT * FROM (SELECT * FROM "test" WHERE i >= 999000 ORDER BY i) AS t1 JOIN (SELECT * FROM "test" WHERE i >= 400000 ORDER BY i) AS t2 ON (TRUE) ORDER BY t1.i, t2.i LIMIT 10;
|
|
SELECT * FROM (SELECT * FROM "test" WHERE i >= 999000 ORDER BY i) AS t1 JOIN (SELECT * FROM "test" WHERE i >= 400000 ORDER BY i) AS t2 ON (TRUE) ORDER BY t1.i, t2.i LIMIT 10;
|
|
|
|
-- Test parallel ChunkAppend reinit
|
|
SET enable_material = off;
|
|
SET min_parallel_table_scan_size = 0;
|
|
SET min_parallel_index_scan_size = 0;
|
|
SET enable_hashjoin = 'off';
|
|
SET enable_nestloop = 'off';
|
|
|
|
CREATE TABLE sensor_data(
|
|
time timestamptz NOT NULL,
|
|
sensor_id integer NOT NULL);
|
|
|
|
SELECT FROM create_hypertable(relation=>'sensor_data', time_column_name=> 'time');
|
|
|
|
-- Sensors 1 and 2
|
|
INSERT INTO sensor_data
|
|
SELECT time, sensor_id
|
|
FROM
|
|
generate_series('2000-01-01 00:00:30', '2022-01-01 00:00:30', INTERVAL '3 months') AS g1(time),
|
|
generate_series(1, 2, 1) AS g2(sensor_id)
|
|
ORDER BY time;
|
|
|
|
-- Sensor 100
|
|
INSERT INTO sensor_data
|
|
SELECT time, 100 as sensor_id
|
|
FROM
|
|
generate_series('2000-01-01 00:00:30', '2022-01-01 00:00:30', INTERVAL '1 year') AS g1(time)
|
|
ORDER BY time;
|
|
|
|
:PREFIX SELECT * FROM sensor_data AS s1 JOIN sensor_data AS s2 ON (TRUE) WHERE s1.time > '2020-01-01 00:00:30'::text::timestamptz AND s2.time > '2020-01-01 00:00:30' AND s2.time < '2021-01-01 00:00:30' AND s1.sensor_id > 50 ORDER BY s2.time, s1.time, s1.sensor_id, s2.sensor_id;
|
|
|
|
-- Check query result
|
|
SELECT * FROM sensor_data AS s1 JOIN sensor_data AS s2 ON (TRUE) WHERE s1.time > '2020-01-01 00:00:30'::text::timestamptz AND s2.time > '2020-01-01 00:00:30' AND s2.time < '2021-01-01 00:00:30' AND s1.sensor_id > 50 ORDER BY s2.time, s1.time, s1.sensor_id, s2.sensor_id;
|
|
|
|
-- Ensure the same result is produced if only the parallel workers have to produce them (i.e., the pstate is reinitialized properly)
|
|
SET parallel_leader_participation = off;
|
|
SELECT * FROM sensor_data AS s1 JOIN sensor_data AS s2 ON (TRUE) WHERE s1.time > '2020-01-01 00:00:30'::text::timestamptz AND s2.time > '2020-01-01 00:00:30' AND s2.time < '2021-01-01 00:00:30' AND s1.sensor_id > 50 ORDER BY s2.time, s1.time, s1.sensor_id, s2.sensor_id;
|
|
RESET parallel_leader_participation;
|
|
|
|
-- Ensure the same query result is produced by a sequencial query
|
|
SET max_parallel_workers_per_gather TO 0;
|
|
SELECT set_config(CASE WHEN current_setting('server_version_num')::int < 160000 THEN 'force_parallel_mode' ELSE 'debug_parallel_query' END,'off', false);
|
|
SELECT * FROM sensor_data AS s1 JOIN sensor_data AS s2 ON (TRUE) WHERE s1.time > '2020-01-01 00:00:30'::text::timestamptz AND s2.time > '2020-01-01 00:00:30' AND s2.time < '2021-01-01 00:00:30' AND s1.sensor_id > 50 ORDER BY s2.time, s1.time, s1.sensor_id, s2.sensor_id;
|
|
|
|
RESET enable_material;
|
|
RESET min_parallel_table_scan_size;
|
|
RESET min_parallel_index_scan_size;
|
|
RESET enable_hashjoin;
|
|
RESET enable_nestloop;
|
|
RESET parallel_tuple_cost;
|
|
SELECT set_config(CASE WHEN current_setting('server_version_num')::int < 160000 THEN 'force_parallel_mode' ELSE 'debug_parallel_query' END,'on', false);
|
|
|
|
-- test worker assignment
|
|
-- first chunk should have 1 worker and second chunk should have 2
|
|
SET max_parallel_workers_per_gather TO 2;
|
|
:PREFIX SELECT count(*) FROM "test" WHERE i >= 400000 AND length(version()) > 0;
|
|
SELECT count(*) FROM "test" WHERE i >= 400000 AND length(version()) > 0;
|
|
|
|
-- test worker assignment
|
|
-- first chunk should have 2 worker and second chunk should have 1
|
|
:PREFIX SELECT count(*) FROM "test" WHERE i < 600000 AND length(version()) > 0;
|
|
SELECT count(*) FROM "test" WHERE i < 600000 AND length(version()) > 0;
|
|
|
|
-- test ChunkAppend with # workers < # childs
|
|
SET max_parallel_workers_per_gather TO 1;
|
|
:PREFIX SELECT count(*) FROM "test" WHERE length(version()) > 0;
|
|
SELECT count(*) FROM "test" WHERE length(version()) > 0;
|
|
|
|
-- test ChunkAppend with # workers > # childs
|
|
SET max_parallel_workers_per_gather TO 2;
|
|
:PREFIX SELECT count(*) FROM "test" WHERE i >= 500000 AND length(version()) > 0;
|
|
SELECT count(*) FROM "test" WHERE i >= 500000 AND length(version()) > 0;
|
|
|
|
RESET max_parallel_workers_per_gather;
|
|
|
|
-- test partial and non-partial plans
|
|
-- these will not be parallel on PG < 11
|
|
ALTER TABLE :CHUNK1 SET (parallel_workers=0);
|
|
ALTER TABLE :CHUNK2 SET (parallel_workers=2);
|
|
:PREFIX SELECT count(*) FROM "test" WHERE i > 400000 AND length(version()) > 0;
|
|
|
|
ALTER TABLE :CHUNK1 SET (parallel_workers=2);
|
|
ALTER TABLE :CHUNK2 SET (parallel_workers=0);
|
|
:PREFIX SELECT count(*) FROM "test" WHERE i < 600000 AND length(version()) > 0;
|
|
|
|
ALTER TABLE :CHUNK1 RESET (parallel_workers);
|
|
ALTER TABLE :CHUNK2 RESET (parallel_workers);
|
|
|
|
-- now() is not marked parallel safe in PostgreSQL < 12 so using now()
|
|
-- in a query will prevent parallelism but CURRENT_TIMESTAMP and
|
|
-- transaction_timestamp() are marked parallel safe
|
|
:PREFIX SELECT i FROM "test" WHERE ts < CURRENT_TIMESTAMP;
|
|
|
|
:PREFIX SELECT i FROM "test" WHERE ts < transaction_timestamp();
|
|
|
|
-- this won't be parallel query because now() is parallel restricted in PG < 12
|
|
:PREFIX SELECT i FROM "test" WHERE ts < now();
|
|
|