SET search_path TO local_dist_join_mixed; -- very simple 1-1 Joins SELECT count(*) FROM distributed JOIN local USING (id); count --------------------------------------------------------------------- 101 (1 row) SELECT count(*) FROM distributed JOIN local ON (name = title); count --------------------------------------------------------------------- 101 (1 row) SELECT count(*) FROM distributed d1 JOIN local ON (name = d1.id::text); count --------------------------------------------------------------------- 10201 (1 row) SELECT count(*) FROM distributed d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int); count --------------------------------------------------------------------- 5050 (1 row) SELECT count(*) FROM distributed d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1; count --------------------------------------------------------------------- 99 (1 row) SELECT count(*) FROM distributed JOIN local USING (id) WHERE false; count --------------------------------------------------------------------- 0 (1 row) SELECT count(*) FROM distributed d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1 OR True; count --------------------------------------------------------------------- 5050 (1 row) SELECT count(*) FROM distributed d1 JOIN local ON (name::int + local.id > d1.id AND d1.id < local.title::int) WHERE d1.id = 1; count --------------------------------------------------------------------- 99 (1 row) SELECT count(*) FROM distributed JOIN local ON (hashtext(name) = hashtext(title)); count --------------------------------------------------------------------- 101 (1 row) SELECT hashtext(local.id::text) FROM distributed JOIN local ON (hashtext(name) = hashtext(title)) ORDER BY 1 LIMIT 4; hashtext --------------------------------------------------------------------- -2114455578 -2097988278 -1997006946 -1985772843 (4 rows) SELECT '' as "xxx", local.*, 'xxx' as "test" FROM distributed JOIN local ON (hashtext(name) = hashtext(title)) ORDER BY 1,2,3 LIMIT 4; xxx | id | title | test --------------------------------------------------------------------- | 0 | 0 | xxx | 1 | 1 | xxx | 2 | 2 | xxx | 3 | 3 | xxx (4 rows) SELECT local.title, count(*) FROM distributed JOIN local USING (id) GROUP BY 1 ORDER BY 1, 2 DESC LIMIT 5; title | count --------------------------------------------------------------------- 0 | 1 1 | 1 10 | 1 100 | 1 11 | 1 (5 rows) SELECT distributed.id as id1, local.id as id2 FROM distributed JOIN local USING(id) ORDER BY distributed.id + local.id LIMIT 5; id1 | id2 --------------------------------------------------------------------- 0 | 0 1 | 1 2 | 2 3 | 3 4 | 4 (5 rows) SELECT distributed.id as id1, local.id as id2, count(*) FROM distributed JOIN local USING(id) GROUP BY distributed.id, local.id ORDER BY 1,2 LIMIT 5; id1 | id2 | count --------------------------------------------------------------------- 0 | 0 | 1 1 | 1 | 1 2 | 2 | 1 3 | 3 | 1 4 | 4 | 1 (5 rows) -- basic subqueries that cannot be pulled up SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local USING (id); count --------------------------------------------------------------------- 101 (1 row) SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local ON (name = title); count --------------------------------------------------------------------- 101 (1 row) SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local ON (name = d1.id::text); count --------------------------------------------------------------------- 10201 (1 row) SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int); count --------------------------------------------------------------------- 5050 (1 row) SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1; count --------------------------------------------------------------------- 99 (1 row) SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1 AND false; count --------------------------------------------------------------------- 0 (1 row) SELECT count(*) FROM (SELECT *, random() FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1 OR true; count --------------------------------------------------------------------- 5050 (1 row) -- pull up subqueries as they are pretty simple, local table should be recursively planned SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local USING (id); count --------------------------------------------------------------------- 101 (1 row) SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local ON (name = title); count --------------------------------------------------------------------- 101 (1 row) SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local ON (name = d1.id::text); count --------------------------------------------------------------------- 10201 (1 row) SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int); count --------------------------------------------------------------------- 5050 (1 row) SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1; count --------------------------------------------------------------------- 99 (1 row) SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1 AND false; count --------------------------------------------------------------------- 0 (1 row) SELECT count(*) FROM (SELECT * FROM distributed) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1 OR true; count --------------------------------------------------------------------- 5050 (1 row) SELECT count(*) FROM (SELECT * FROM distributed WHERE id = 2) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1; count --------------------------------------------------------------------- 0 (1 row) SELECT count(*) FROM (SELECT * FROM distributed WHERE false) as d1 JOIN local ON (name = d1.id::text AND d1.id < local.title::int) WHERE d1.id = 1; count --------------------------------------------------------------------- 0 (1 row) -- final queries are pushdown queries SELECT sum(d1.id + local.id) FROM distributed d1 JOIN local USING (id); sum --------------------------------------------------------------------- 10100 (1 row) SELECT sum(d1.id + local.id) OVER (PARTITION BY d1.id) FROM distributed d1 JOIN local USING (id) ORDER BY 1 DESC LIMIT 4; sum --------------------------------------------------------------------- 200 198 196 194 (4 rows) SELECT count(*) FROM distributed d1 JOIN local USING (id) LEFT JOIN distributed d2 USING (id) ORDER BY 1 DESC LIMIT 4; count --------------------------------------------------------------------- 101 (1 row) SELECT count(DISTINCT d1.name::int * local.id) FROM distributed d1 JOIN local USING (id); count --------------------------------------------------------------------- 101 (1 row) -- final queries are router queries SELECT sum(d1.id + local.id) FROM distributed d1 JOIN local USING (id) WHERE d1.id = 1; sum --------------------------------------------------------------------- 2 (1 row) SELECT sum(d1.id + local.id) OVER (PARTITION BY d1.id) FROM distributed d1 JOIN local USING (id) WHERE d1.id = 1 ORDER BY 1 DESC LIMIT 4; sum --------------------------------------------------------------------- 2 (1 row) SELECT count(*) FROM distributed d1 JOIN local USING (id) LEFT JOIN distributed d2 USING (id) WHERE d2.id = 1 ORDER BY 1 DESC LIMIT 4; count --------------------------------------------------------------------- 1 (1 row) -- final queries are pull to coordinator queries SELECT sum(d1.id + local.id) OVER (PARTITION BY d1.id + local.id) FROM distributed d1 JOIN local USING (id) ORDER BY 1 DESC LIMIT 4; sum --------------------------------------------------------------------- 200 198 196 194 (4 rows) -- nested subqueries SELECT count(*) FROM (SELECT * FROM (SELECT * FROM distributed) as foo) as bar JOIN local USING(id); count --------------------------------------------------------------------- 101 (1 row) SELECT count(*) FROM (SELECT *, random() FROM (SELECT *, random() FROM distributed) as foo) as bar JOIN local USING(id); count --------------------------------------------------------------------- 101 (1 row) SELECT count(*) FROM (SELECT *, random() FROM (SELECT *, random() FROM distributed) as foo) as bar JOIN local USING(id); count --------------------------------------------------------------------- 101 (1 row) SELECT count(*) FROM (SELECT *, random() FROM (SELECT *, random() FROM distributed) as foo) as bar JOIN (SELECT *, random() FROM (SELECT *,random() FROM local) as foo2) as bar2 USING(id); count --------------------------------------------------------------------- 101 (1 row) -- TODO: Unnecessary recursive planning for local SELECT count(*) FROM (SELECT *, random() FROM (SELECT *, random() FROM distributed LIMIT 1) as foo) as bar JOIN (SELECT *, random() FROM (SELECT *,random() FROM local) as foo2) as bar2 USING(id); count --------------------------------------------------------------------- 1 (1 row) -- subqueries in WHERE clause -- is not colocated, and the JOIN inside as well. -- so should be recursively planned twice SELECT count(*) FROM distributed WHERE id > (SELECT count(*) FROM (SELECT *, random() FROM (SELECT *, random() FROM distributed) as foo) as bar JOIN (SELECT *, random() FROM (SELECT *,random() FROM local) as foo2) as bar2 USING(id) ); count --------------------------------------------------------------------- 0 (1 row) -- two distributed tables are co-located and JOINed on distribution -- key, so should be fine to pushdown SELECT count(*) FROM distributed d_upper WHERE (SELECT bar.id FROM (SELECT *, random() FROM (SELECT *, random() FROM distributed WHERE distributed.id = d_upper.id) as foo) as bar JOIN (SELECT *, random() FROM (SELECT *,random() FROM local) as foo2) as bar2 USING(id) ) IS NOT NULL; count --------------------------------------------------------------------- 101 (1 row) SELECT count(*) FROM distributed d_upper WHERE (SELECT bar.id FROM (SELECT *, random() FROM (SELECT *, random() FROM distributed WHERE distributed.id = d_upper.id) as foo) as bar JOIN local as foo USING(id) ) IS NOT NULL; count --------------------------------------------------------------------- 101 (1 row) SELECT count(*) FROM distributed d_upper WHERE d_upper.id > (SELECT bar.id FROM (SELECT *, random() FROM (SELECT *, random() FROM distributed WHERE distributed.id = d_upper.id) as foo) as bar JOIN local as foo USING(id) ); count --------------------------------------------------------------------- 0 (1 row) -- subqueries in the target list -- router, should work select (SELECT local.id) FROM local, distributed WHERE distributed.id = 1 LIMIT 1; id --------------------------------------------------------------------- 0 (1 row) -- set operations SELECT local.* FROM distributed JOIN local USING (id) EXCEPT SELECT local.* FROM distributed JOIN local USING (id); id | title --------------------------------------------------------------------- (0 rows) SELECT distributed.* FROM distributed JOIN local USING (id) EXCEPT SELECT distributed.* FROM distributed JOIN local USING (id); id | name | created_at --------------------------------------------------------------------- (0 rows) SELECT count(*) FROM ( (SELECT * FROM (SELECT * FROM local) as f JOIN distributed USING (id)) UNION ALL (SELECT * FROM (SELECT * FROM local) as f2 JOIN distributed USING (id)) ) bar; count --------------------------------------------------------------------- 202 (1 row) SELECT count(*) FROM ( (SELECT * FROM (SELECT distributed.* FROM local JOIN distributed USING (id)) as fo) UNION ALL (SELECT * FROM (SELECT distributed.* FROM local JOIN distributed USING (id)) as ba) ) bar; count --------------------------------------------------------------------- 202 (1 row) select count(DISTINCT id) FROM ( (SELECT * FROM (SELECT distributed.* FROM local JOIN distributed USING (id)) as fo) UNION ALL (SELECT * FROM (SELECT distributed.* FROM local JOIN distributed USING (id)) as ba) ) bar; count --------------------------------------------------------------------- 101 (1 row) -- lateral joins SELECT COUNT(*) FROM local JOIN LATERAL (SELECT * FROM distributed WHERE local.id = distributed.id) as foo ON (true); count --------------------------------------------------------------------- 101 (1 row) SELECT COUNT(*) FROM local JOIN LATERAL (SELECT * FROM distributed WHERE local.id > distributed.id) as foo ON (true); count --------------------------------------------------------------------- 5050 (1 row) SELECT count(*) FROM distributed CROSS JOIN local; count --------------------------------------------------------------------- 10201 (1 row) SELECT count(*) FROM distributed CROSS JOIN local WHERE distributed.id = 1; count --------------------------------------------------------------------- 101 (1 row) -- w count(*) it works fine as PG ignores the inner tables SELECT count(*) FROM distributed LEFT JOIN local USING (id); count --------------------------------------------------------------------- 101 (1 row) SELECT count(*) FROM local LEFT JOIN distributed USING (id); count --------------------------------------------------------------------- 101 (1 row) SELECT id, name FROM distributed LEFT JOIN local USING (id) ORDER BY 1 LIMIT 1; id | name --------------------------------------------------------------------- 0 | 0 (1 row) SELECT foo1.id FROM (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo9, (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo8, (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo7, (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo6, (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo5, (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo4, (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo3, (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo2, (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo10, (SELECT local.id, local.title FROM local, distributed WHERE local.id = distributed.id ) as foo1 WHERE foo1.id = foo9.id AND foo1.id = foo8.id AND foo1.id = foo7.id AND foo1.id = foo6.id AND foo1.id = foo5.id AND foo1.id = foo4.id AND foo1.id = foo3.id AND foo1.id = foo2.id AND foo1.id = foo10.id AND foo1.id = foo1.id ORDER BY 1; id --------------------------------------------------------------------- 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 (101 rows) SELECT foo1.id FROM (SELECT local.id FROM distributed, local WHERE local.id = distributed.id ) as foo1, (SELECT local.id FROM distributed, local WHERE local.id = distributed.id ) as foo2, (SELECT local.id FROM distributed, local WHERE local.id = distributed.id ) as foo3, (SELECT local.id FROM distributed, local WHERE local.id = distributed.id ) as foo4, (SELECT local.id FROM distributed, local WHERE local.id = distributed.id ) as foo5 WHERE foo1.id = foo4.id AND foo1.id = foo2.id AND foo1.id = foo3.id AND foo1.id = foo4.id AND foo1.id = foo5.id ORDER BY 1; id --------------------------------------------------------------------- 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 (101 rows) SELECT foo1.id FROM (SELECT local.id FROM distributed, local WHERE local.id = distributed.id AND distributed.id = 1) as foo1, (SELECT local.id FROM distributed, local WHERE local.id = distributed.id AND distributed.id = 2) as foo2, (SELECT local.id FROM distributed, local WHERE local.id = distributed.id AND distributed.id = 3) as foo3, (SELECT local.id FROM distributed, local WHERE local.id = distributed.id AND distributed.id = 4) as foo4, (SELECT local.id FROM distributed, local WHERE local.id = distributed.id AND distributed.id = 5) as foo5 WHERE foo1.id = foo4.id AND foo1.id = foo2.id AND foo1.id = foo3.id AND foo1.id = foo4.id AND foo1.id = foo5.id ORDER BY 1; id --------------------------------------------------------------------- (0 rows) --https://github.com/citusdata/citus/issues/5384 -- SELECT -- count(*) -- FROM -- distributed -- JOIN LATERAL -- (SELECT -- * -- FROM -- local -- JOIN -- distributed d2 -- ON(true) -- WHERE local.id = distributed.id AND d2.id = local.id) as foo -- ON (true); SELECT local.title, local.title FROM local JOIN distributed USING(id) ORDER BY 1,2 LIMIt 1; title | title --------------------------------------------------------------------- 0 | 0 (1 row) SELECT NULL FROM local JOIN distributed USING(id) ORDER BY 1 LIMIt 1; ?column? --------------------------------------------------------------------- (1 row) SELECT distributed.name, distributed.name, local.title, local.title FROM local JOIN distributed USING(id) ORDER BY 1,2,3,4 LIMIT 1; name | name | title | title --------------------------------------------------------------------- 0 | 0 | 0 | 0 (1 row) BEGIN; SELECT COUNT(DISTINCT title) FROM local; count --------------------------------------------------------------------- 101 (1 row) UPDATE local SET title = 'test' FROM distributed WHERE distributed.id = local.id; SELECT COUNT(DISTINCT title) FROM local; count --------------------------------------------------------------------- 1 (1 row) ROLLBACK; BEGIN; SELECT COUNT(DISTINCT name) FROM distributed; count --------------------------------------------------------------------- 101 (1 row) UPDATE distributed SET name = 'test' FROM local WHERE distributed.id = local.id; SELECT COUNT(DISTINCT name) FROM distributed; count --------------------------------------------------------------------- 1 (1 row) ROLLBACK; BEGIN; SELECT COUNT(DISTINCT name) FROM distributed; count --------------------------------------------------------------------- 101 (1 row) UPDATE distributed SET name = 'test' FROM local WHERE distributed.id = local.id; SELECT COUNT(DISTINCT name) FROM distributed; count --------------------------------------------------------------------- 1 (1 row) ROLLBACK; BEGIN; SELECT COUNT(DISTINCT name) FROM distributed; count --------------------------------------------------------------------- 101 (1 row) UPDATE distributed SET name = 'test' FROM local WHERE distributed.id = local.id; SELECT COUNT(DISTINCT name) FROM distributed; count --------------------------------------------------------------------- 1 (1 row) ROLLBACK;