| -- 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; |