Skip to content

Commit

Permalink
Add Parallel hint tests for empty tables.
Browse files Browse the repository at this point in the history
As a result of the discussion with Sami Imseih, this commit adds tests
showing that for empty tables, only parallel index scans can be enforced
and not sequential scans.  This is an old, historical, rather weird
behavior, that may not be worth changing in the long run as empry tables
are not something users rely a lot when using pg_hint_plan, but let's
add a test tracking if any future change impacts the plans generated.

Author: Sami Imseih
Backpatch-through: 17

Per discussion on issue #164.
  • Loading branch information
michaelpq committed Aug 20, 2024
1 parent 48a71d4 commit e92d75f
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 0 deletions.
74 changes: 74 additions & 0 deletions expected/ut-W.out
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,80 @@ error hint:
-> Parallel Seq Scan on p2_c3_c2 p2_8
(21 rows)

-- On empty tables, parallel hints can only be enforced for index scans
-- and not sequential scans. Adding a single row allows a parallel
-- hint to be enforced on a sequential scan. It is a bit weird that
-- having no rows controls how parallel workers are triggered, but
-- at the same time we have nothing to query, and this is an old
-- historical (and accidental) behavior.
/*+Parallel(t5 4 hard) Parallel(t6 2 hard)*/
EXPLAIN (COSTS false) SELECT * FROM s1.t5 NATURAL JOIN s1.t6;
LOG: pg_hint_plan:
used hint:
Parallel(t5 4 hard)
Parallel(t6 2 hard)
not used hint:
duplication hint:
error hint:

QUERY PLAN
----------------------------------------------------------------------------------------------
Nested Loop
Join Filter: ((t5.c1 = t6.c1) AND (t6.c2 = t5.c2) AND (t6.c3 = t5.c3) AND (t6.c4 = t5.c4))
-> Seq Scan on t5
-> Seq Scan on t6
(4 rows)

/*+Parallel(t5 4 hard) Parallel(t6 2 hard) NoSeqScan(t5) NoSeqScan(t6) */
EXPLAIN (COSTS false) SELECT * FROM s1.t5 NATURAL JOIN s1.t6;
LOG: pg_hint_plan:
used hint:
NoSeqScan(t5)
NoSeqScan(t6)
Parallel(t5 4 hard)
Parallel(t6 2 hard)
not used hint:
duplication hint:
error hint:

QUERY PLAN
----------------------------------------------------------------------------------------------
Nested Loop
Join Filter: ((t5.c1 = t6.c1) AND (t6.c2 = t5.c2) AND (t6.c3 = t5.c3) AND (t6.c4 = t5.c4))
-> Gather
Workers Planned: 4
-> Parallel Index Scan using t5_pkey on t5
-> Gather
Workers Planned: 2
-> Parallel Index Scan using t6_pkey on t6
(8 rows)

INSERT INTO s1.t5 SELECT i, i, i % 10, i FROM (SELECT generate_series(1, 1) i) t;
INSERT INTO s1.t6 SELECT i, i, i % 10, i FROM (SELECT generate_series(1, 1) i) t;
ANALYZE s1.t5;
ANALYZE s1.t6;
/*+Parallel(t5 4 hard) Parallel(t6 2 hard)*/
EXPLAIN (COSTS false) SELECT * FROM s1.t5 NATURAL JOIN s1.t6;
LOG: pg_hint_plan:
used hint:
Parallel(t5 4 hard)
Parallel(t6 2 hard)
not used hint:
duplication hint:
error hint:

QUERY PLAN
----------------------------------------------------------------------------------------------
Nested Loop
Join Filter: ((t5.c1 = t6.c1) AND (t6.c2 = t5.c2) AND (t6.c3 = t5.c3) AND (t6.c4 = t5.c4))
-> Gather
Workers Planned: 4
-> Parallel Seq Scan on t5
-> Gather
Workers Planned: 2
-> Parallel Seq Scan on t6
(8 rows)

-- Negative hints
SET enable_indexscan to DEFAULT;
SET parallel_setup_cost to 0;
Expand Down
4 changes: 4 additions & 0 deletions expected/ut-init.out
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ CREATE TABLE s1.t1 (c1 int, c2 int, c3 int, c4 text, PRIMARY KEY (c1));
CREATE TABLE s1.t2 (LIKE s1.t1 INCLUDING ALL);
CREATE TABLE s1.t3 (LIKE s1.t1 INCLUDING ALL);
CREATE TABLE s1.t4 (LIKE s1.t1 INCLUDING ALL);
CREATE TABLE s1.t5 (LIKE s1.t1 INCLUDING ALL);
CREATE TABLE s1.t6 (LIKE s1.t1 INCLUDING ALL);
CREATE TABLE s2.t1 (LIKE s1.t1 INCLUDING ALL);
CREATE TABLE s1.p1 (LIKE s1.t1 INCLUDING ALL);
CREATE UNIQUE INDEX p1_parent ON s1.p1 USING btree (c4 COLLATE "C" varchar_ops ASC NULLS LAST, (c1 * 2 < 100)) WHERE c1 < 10;
Expand Down Expand Up @@ -180,6 +182,8 @@ ANALYZE s1.p2c3c1;
ANALYZE s1.p2c3c2;
ANALYZE s1.ti1;
ANALYZE s1.pt1;
ANALYZE s1.t5;
ANALYZE s1.t6;
CREATE FUNCTION s1.f1 () RETURNS s1.t1 AS $$
VALUES(1,1,1,'1'), (2,2,2,'2'), (3,3,3,'3')
$$ LANGUAGE sql;
Expand Down
16 changes: 16 additions & 0 deletions sql/ut-W.sql
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,22 @@ SET max_parallel_workers_per_gather to 8;
/*+Parallel(p1 5 hard)Parallel(p2 6 hard) */
EXPLAIN (COSTS false) SELECT id FROM p1 UNION ALL SELECT id FROM p2;

-- On empty tables, parallel hints can only be enforced for index scans
-- and not sequential scans. Adding a single row allows a parallel
-- hint to be enforced on a sequential scan. It is a bit weird that
-- having no rows controls how parallel workers are triggered, but
-- at the same time we have nothing to query, and this is an old
-- historical (and accidental) behavior.
/*+Parallel(t5 4 hard) Parallel(t6 2 hard)*/
EXPLAIN (COSTS false) SELECT * FROM s1.t5 NATURAL JOIN s1.t6;
/*+Parallel(t5 4 hard) Parallel(t6 2 hard) NoSeqScan(t5) NoSeqScan(t6) */
EXPLAIN (COSTS false) SELECT * FROM s1.t5 NATURAL JOIN s1.t6;
INSERT INTO s1.t5 SELECT i, i, i % 10, i FROM (SELECT generate_series(1, 1) i) t;
INSERT INTO s1.t6 SELECT i, i, i % 10, i FROM (SELECT generate_series(1, 1) i) t;
ANALYZE s1.t5;
ANALYZE s1.t6;
/*+Parallel(t5 4 hard) Parallel(t6 2 hard)*/
EXPLAIN (COSTS false) SELECT * FROM s1.t5 NATURAL JOIN s1.t6;

-- Negative hints
SET enable_indexscan to DEFAULT;
Expand Down
4 changes: 4 additions & 0 deletions sql/ut-init.sql
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ CREATE TABLE s1.t1 (c1 int, c2 int, c3 int, c4 text, PRIMARY KEY (c1));
CREATE TABLE s1.t2 (LIKE s1.t1 INCLUDING ALL);
CREATE TABLE s1.t3 (LIKE s1.t1 INCLUDING ALL);
CREATE TABLE s1.t4 (LIKE s1.t1 INCLUDING ALL);
CREATE TABLE s1.t5 (LIKE s1.t1 INCLUDING ALL);
CREATE TABLE s1.t6 (LIKE s1.t1 INCLUDING ALL);
CREATE TABLE s2.t1 (LIKE s1.t1 INCLUDING ALL);
CREATE TABLE s1.p1 (LIKE s1.t1 INCLUDING ALL);
CREATE UNIQUE INDEX p1_parent ON s1.p1 USING btree (c4 COLLATE "C" varchar_ops ASC NULLS LAST, (c1 * 2 < 100)) WHERE c1 < 10;
Expand Down Expand Up @@ -135,6 +137,8 @@ ANALYZE s1.p2c3c1;
ANALYZE s1.p2c3c2;
ANALYZE s1.ti1;
ANALYZE s1.pt1;
ANALYZE s1.t5;
ANALYZE s1.t6;

CREATE FUNCTION s1.f1 () RETURNS s1.t1 AS $$
VALUES(1,1,1,'1'), (2,2,2,'2'), (3,3,3,'3')
Expand Down

0 comments on commit e92d75f

Please sign in to comment.