blob: 867b5c60e9a33006667923b559cf520484bd34c8 [file]
-- start_matchsubs
-- m/\(actual rows=[^)]*\)/
-- s/\(actual rows=[^)]*\)/(actual rows=...)/
-- end_matchsubs
-- start_matchignore
-- m/^\s*Buckets: \d+ Batches: \d+ Memory Usage: \d+kB/
-- end_matchignore
CREATE EXTENSION parallel_customscan;
-- Set up data BEFORE enabling our hook so ANALYZE doesn't traverse it.
CREATE TABLE pcs_t (a int)
WITH (parallel_workers = 2)
DISTRIBUTED BY (a);
INSERT INTO pcs_t SELECT generate_series(1, 1000);
ANALYZE pcs_t;
SET optimizer = off;
SET enable_parallel = on;
SET enable_seqscan = off;
SET min_parallel_table_scan_size = 0;
SET parallel_setup_cost = 0;
SET parallel_tuple_cost = 0;
SET max_parallel_workers_per_gather = 2;
-- (1) Enabling the hook replaces the Parallel Seq Scan with a Custom Scan.
EXPLAIN (COSTS OFF) SELECT count(*) FROM pcs_t;
QUERY PLAN
------------------------------------------------
Finalize Aggregate
-> Gather Motion 6:1 (slice1; segments: 6)
-> Partial Aggregate
-> Parallel Seq Scan on pcs_t
Optimizer: Postgres query optimizer
(5 rows)
SET parallel_customscan.enabled = on;
EXPLAIN (COSTS OFF) SELECT count(*) FROM pcs_t;
QUERY PLAN
-------------------------------------------------------------
Finalize Aggregate
-> Gather Motion 6:1 (slice1; segments: 6)
-> Partial Aggregate
-> Parallel Custom Scan (ParallelCustomScan)
-> Parallel Seq Scan on pcs_t
Optimizer: Postgres query optimizer
(6 rows)
-- (2) Correctness: results match only if every parallel worker runs our scan.
SELECT count(*) FROM pcs_t;
count
-------
1000
(1 row)
SELECT sum(a) FROM pcs_t;
sum
--------
500500
(1 row)
-- (3) Scan-level qualifier and projection through the custom scan.
EXPLAIN (COSTS OFF) SELECT a FROM pcs_t WHERE a > 990;
QUERY PLAN
-------------------------------------------------
Gather Motion 6:1 (slice1; segments: 6)
-> Parallel Custom Scan (ParallelCustomScan)
-> Parallel Seq Scan on pcs_t
Filter: (a > 990)
Optimizer: Postgres query optimizer
(5 rows)
SELECT a FROM pcs_t WHERE a > 990 ORDER BY a;
a
------
991
992
993
994
995
996
997
998
999
1000
(10 rows)
SELECT count(*) FROM pcs_t WHERE a % 2 = 0;
count
-------
500
(1 row)
-- (4) Join with both inputs scanned by the custom scan, plus a scan-level qual.
CREATE TABLE pcs_t2 (a int)
WITH (parallel_workers = 2)
DISTRIBUTED BY (a);
INSERT INTO pcs_t2 SELECT generate_series(1, 500);
ANALYZE pcs_t2;
EXPLAIN (COSTS OFF)
SELECT count(*) FROM pcs_t x JOIN pcs_t2 y ON x.a = y.a WHERE x.a <= 100;
QUERY PLAN
-------------------------------------------------------------------------
Finalize Aggregate
-> Gather Motion 6:1 (slice1; segments: 6)
-> Partial Aggregate
-> Parallel Hash Join
Hash Cond: (x.a = y.a)
-> Parallel Custom Scan (ParallelCustomScan)
-> Parallel Seq Scan on pcs_t x
Filter: (a <= 100)
-> Parallel Hash
-> Parallel Custom Scan (ParallelCustomScan)
-> Parallel Seq Scan on pcs_t2 y
Filter: (a <= 100)
Optimizer: Postgres query optimizer
(13 rows)
SELECT count(*) FROM pcs_t x JOIN pcs_t2 y ON x.a = y.a WHERE x.a <= 100;
count
-------
100
(1 row)
-- (5) Empty relation: the custom scan must handle an immediate end-of-scan.
CREATE TABLE pcs_empty (a int)
WITH (parallel_workers = 2)
DISTRIBUTED BY (a);
ANALYZE pcs_empty;
EXPLAIN (COSTS OFF) SELECT count(*) FROM pcs_empty;
QUERY PLAN
------------------------------------------------
Aggregate
-> Gather Motion 3:1 (slice1; segments: 3)
-> Custom Scan (ParallelCustomScan)
-> Seq Scan on pcs_empty
Optimizer: Postgres query optimizer
(5 rows)
SELECT count(*) FROM pcs_empty;
count
-------
0
(1 row)
SELECT * FROM pcs_empty;
a
---
(0 rows)
-- (6) Serial path: with no workers, a non-parallel Custom Scan is used.
SET max_parallel_workers_per_gather = 0;
EXPLAIN (COSTS OFF) SELECT count(*) FROM pcs_t;
QUERY PLAN
----------------------------------------------------
Finalize Aggregate
-> Gather Motion 3:1 (slice1; segments: 3)
-> Partial Aggregate
-> Custom Scan (ParallelCustomScan)
-> Seq Scan on pcs_t
Optimizer: Postgres query optimizer
(6 rows)
SELECT count(*) FROM pcs_t;
count
-------
1000
(1 row)
SELECT a FROM pcs_t WHERE a > 995 ORDER BY a;
a
------
996
997
998
999
1000
(5 rows)
SET max_parallel_workers_per_gather = 2;
-- (7) EXPLAIN ANALYZE: exercises planstate_walk_kids' custom_ps recursion.
EXPLAIN (ANALYZE, TIMING OFF, COSTS OFF, SUMMARY OFF)
SELECT count(*) FROM pcs_t;
QUERY PLAN
---------------------------------------------------------------------------------------
Finalize Aggregate (actual rows=1 loops=1)
-> Gather Motion 6:1 (slice1; segments: 6) (actual rows=6 loops=1)
-> Partial Aggregate (actual rows=1 loops=1)
-> Parallel Custom Scan (ParallelCustomScan) (actual rows=340 loops=1)
-> Parallel Seq Scan on pcs_t (actual rows=340 loops=1)
Optimizer: Postgres query optimizer
(6 rows)
EXPLAIN (ANALYZE, TIMING OFF, COSTS OFF, SUMMARY OFF)
SELECT count(*) FROM pcs_t x JOIN pcs_t2 y ON x.a = y.a;
QUERY PLAN
-------------------------------------------------------------------------------------------------
Finalize Aggregate (actual rows=1 loops=1)
-> Gather Motion 6:1 (slice1; segments: 6) (actual rows=6 loops=1)
-> Partial Aggregate (actual rows=1 loops=1)
-> Parallel Hash Join (actual rows=0 loops=1)
Hash Cond: (x.a = y.a)
-> Parallel Custom Scan (ParallelCustomScan) (actual rows=340 loops=1)
-> Parallel Seq Scan on pcs_t x (actual rows=340 loops=1)
-> Parallel Hash (actual rows=0 loops=1)
Buckets: 524288 Batches: 1 Memory Usage: 4128kB
-> Parallel Custom Scan (ParallelCustomScan) (actual rows=0 loops=1)
-> Parallel Seq Scan on pcs_t2 y (actual rows=0 loops=1)
Optimizer: Postgres query optimizer
(12 rows)
-- cleanup
DROP TABLE pcs_t2;
DROP TABLE pcs_empty;
DROP TABLE pcs_t;
DROP EXTENSION parallel_customscan;