|
| 1 | +/* |
| 2 | + * Since 8edd0e794 (>= 12) Append nodes with single subplan are eliminated, |
| 3 | + * causing different output; pathman_gaps_1.out is the updated version. |
| 4 | + */ |
| 5 | +\set VERBOSITY terse |
| 6 | +SET search_path = 'public'; |
| 7 | +CREATE SCHEMA pathman; |
| 8 | +CREATE EXTENSION pg_pathman SCHEMA pathman; |
| 9 | +CREATE SCHEMA test; |
| 10 | +/* |
| 11 | + * Test push down a join clause into child nodes of append |
| 12 | + */ |
| 13 | +/* create test tables */ |
| 14 | +CREATE TABLE test.fk ( |
| 15 | + id1 INT NOT NULL, |
| 16 | + id2 INT NOT NULL, |
| 17 | + start_key INT, |
| 18 | + end_key INT, |
| 19 | + PRIMARY KEY (id1, id2)); |
| 20 | +CREATE TABLE test.mytbl ( |
| 21 | + id1 INT NOT NULL, |
| 22 | + id2 INT NOT NULL, |
| 23 | + key INT NOT NULL, |
| 24 | + CONSTRAINT fk_fk FOREIGN KEY (id1, id2) REFERENCES test.fk(id1, id2), |
| 25 | + PRIMARY KEY (id1, key)); |
| 26 | +SELECT pathman.create_hash_partitions('test.mytbl', 'id1', 8); |
| 27 | + create_hash_partitions |
| 28 | +------------------------ |
| 29 | + 8 |
| 30 | +(1 row) |
| 31 | + |
| 32 | +/* ...fill out with test data */ |
| 33 | +INSERT INTO test.fk VALUES (1, 1); |
| 34 | +INSERT INTO test.mytbl VALUES (1, 1, 5), (1, 1, 6); |
| 35 | +/* gather statistics on test tables to have deterministic plans */ |
| 36 | +ANALYZE; |
| 37 | +/* run test queries */ |
| 38 | +EXPLAIN (COSTS OFF) /* test plan */ |
| 39 | +SELECT m.tableoid::regclass, id1, id2, key, start_key, end_key |
| 40 | +FROM test.mytbl m JOIN test.fk USING(id1, id2) |
| 41 | +WHERE NOT key <@ int4range(6, end_key); |
| 42 | + QUERY PLAN |
| 43 | +------------------------------------------------------------------------------------------------------- |
| 44 | + Nested Loop |
| 45 | + -> Seq Scan on fk |
| 46 | + -> Custom Scan (RuntimeAppend) |
| 47 | + Prune by: (m.id1 = fk.id1) |
| 48 | + -> Seq Scan on mytbl_0 m |
| 49 | + Filter: ((id1 = fk.id1) AND (fk.id2 = id2) AND (NOT (key <@ int4range(6, fk.end_key)))) |
| 50 | + -> Seq Scan on mytbl_1 m |
| 51 | + Filter: ((id1 = fk.id1) AND (fk.id2 = id2) AND (NOT (key <@ int4range(6, fk.end_key)))) |
| 52 | + -> Seq Scan on mytbl_2 m |
| 53 | + Filter: ((id1 = fk.id1) AND (fk.id2 = id2) AND (NOT (key <@ int4range(6, fk.end_key)))) |
| 54 | + -> Seq Scan on mytbl_3 m |
| 55 | + Filter: ((id1 = fk.id1) AND (fk.id2 = id2) AND (NOT (key <@ int4range(6, fk.end_key)))) |
| 56 | + -> Seq Scan on mytbl_4 m |
| 57 | + Filter: ((id1 = fk.id1) AND (fk.id2 = id2) AND (NOT (key <@ int4range(6, fk.end_key)))) |
| 58 | + -> Seq Scan on mytbl_5 m |
| 59 | + Filter: ((id1 = fk.id1) AND (fk.id2 = id2) AND (NOT (key <@ int4range(6, fk.end_key)))) |
| 60 | + -> Seq Scan on mytbl_6 m |
| 61 | + Filter: ((id1 = fk.id1) AND (fk.id2 = id2) AND (NOT (key <@ int4range(6, fk.end_key)))) |
| 62 | + -> Seq Scan on mytbl_7 m |
| 63 | + Filter: ((id1 = fk.id1) AND (fk.id2 = id2) AND (NOT (key <@ int4range(6, fk.end_key)))) |
| 64 | +(20 rows) |
| 65 | + |
| 66 | +/* test joint data */ |
| 67 | +SELECT m.tableoid::regclass, id1, id2, key, start_key, end_key |
| 68 | +FROM test.mytbl m JOIN test.fk USING(id1, id2) |
| 69 | +WHERE NOT key <@ int4range(6, end_key); |
| 70 | + tableoid | id1 | id2 | key | start_key | end_key |
| 71 | +--------------+-----+-----+-----+-----------+--------- |
| 72 | + test.mytbl_6 | 1 | 1 | 5 | | |
| 73 | +(1 row) |
| 74 | + |
| 75 | +/* |
| 76 | + * Test case by @dimarick |
| 77 | + */ |
| 78 | +CREATE TABLE test.parent ( |
| 79 | + id SERIAL NOT NULL, |
| 80 | + owner_id INTEGER NOT NULL |
| 81 | +); |
| 82 | +CREATE TABLE test.child ( |
| 83 | + parent_id INTEGER NOT NULL, |
| 84 | + owner_id INTEGER NOT NULL |
| 85 | +); |
| 86 | +CREATE TABLE test.child_nopart ( |
| 87 | + parent_id INTEGER NOT NULL, |
| 88 | + owner_id INTEGER NOT NULL |
| 89 | +); |
| 90 | +INSERT INTO test.parent (owner_id) VALUES (1), (2), (3), (3); |
| 91 | +INSERT INTO test.child (parent_id, owner_id) VALUES (1, 1), (2, 2), (3, 3), (5, 3); |
| 92 | +INSERT INTO test.child_nopart (parent_id, owner_id) VALUES (1, 1), (2, 2), (3, 3), (5, 3); |
| 93 | +SELECT pathman.create_hash_partitions('test.child', 'owner_id', 2); |
| 94 | + create_hash_partitions |
| 95 | +------------------------ |
| 96 | + 2 |
| 97 | +(1 row) |
| 98 | + |
| 99 | +/* gather statistics on test tables to have deterministic plans */ |
| 100 | +ANALYZE; |
| 101 | +/* Query #1 */ |
| 102 | +EXPLAIN (COSTS OFF) SELECT * FROM test.parent |
| 103 | +LEFT JOIN test.child ON test.child.parent_id = test.parent.id AND |
| 104 | + test.child.owner_id = test.parent.owner_id |
| 105 | +WHERE test.parent.owner_id = 3 and test.parent.id IN (3, 4); |
| 106 | + QUERY PLAN |
| 107 | +----------------------------------------------------------------------------------------------------- |
| 108 | + Nested Loop Left Join |
| 109 | + -> Seq Scan on parent |
| 110 | + Filter: ((id = ANY ('{3,4}'::integer[])) AND (owner_id = 3)) |
| 111 | + -> Custom Scan (RuntimeAppend) |
| 112 | + Prune by: ((child.owner_id = 3) AND (child.owner_id = parent.owner_id)) |
| 113 | + -> Seq Scan on child_1 child |
| 114 | + Filter: ((owner_id = 3) AND (owner_id = parent.owner_id) AND (parent_id = parent.id)) |
| 115 | +(7 rows) |
| 116 | + |
| 117 | +SELECT * FROM test.parent |
| 118 | +LEFT JOIN test.child ON test.child.parent_id = test.parent.id AND |
| 119 | + test.child.owner_id = test.parent.owner_id |
| 120 | +WHERE test.parent.owner_id = 3 and test.parent.id IN (3, 4); |
| 121 | + id | owner_id | parent_id | owner_id |
| 122 | +----+----------+-----------+---------- |
| 123 | + 3 | 3 | 3 | 3 |
| 124 | + 4 | 3 | | |
| 125 | +(2 rows) |
| 126 | + |
| 127 | +/* Query #2 */ |
| 128 | +EXPLAIN (COSTS OFF) SELECT * FROM test.parent |
| 129 | +LEFT JOIN test.child ON test.child.parent_id = test.parent.id AND |
| 130 | + test.child.owner_id = 3 |
| 131 | +WHERE test.parent.owner_id = 3 and test.parent.id IN (3, 4); |
| 132 | + QUERY PLAN |
| 133 | +---------------------------------------------------------------------- |
| 134 | + Nested Loop Left Join |
| 135 | + Join Filter: (child.parent_id = parent.id) |
| 136 | + -> Seq Scan on parent |
| 137 | + Filter: ((id = ANY ('{3,4}'::integer[])) AND (owner_id = 3)) |
| 138 | + -> Seq Scan on child_1 child |
| 139 | + Filter: (owner_id = 3) |
| 140 | +(6 rows) |
| 141 | + |
| 142 | +SELECT * FROM test.parent |
| 143 | +LEFT JOIN test.child ON test.child.parent_id = test.parent.id AND |
| 144 | + test.child.owner_id = 3 |
| 145 | +WHERE test.parent.owner_id = 3 and test.parent.id IN (3, 4); |
| 146 | + id | owner_id | parent_id | owner_id |
| 147 | +----+----------+-----------+---------- |
| 148 | + 3 | 3 | 3 | 3 |
| 149 | + 4 | 3 | | |
| 150 | +(2 rows) |
| 151 | + |
| 152 | +DROP TABLE test.child CASCADE; |
| 153 | +NOTICE: drop cascades to 2 other objects |
| 154 | +DROP TABLE test.child_nopart CASCADE; |
| 155 | +DROP TABLE test.mytbl CASCADE; |
| 156 | +NOTICE: drop cascades to 8 other objects |
| 157 | +DROP TABLE test.fk CASCADE; |
| 158 | +DROP TABLE test.parent CASCADE; |
| 159 | +DROP SCHEMA test; |
| 160 | +DROP EXTENSION pg_pathman CASCADE; |
| 161 | +DROP SCHEMA pathman; |
0 commit comments