CREATE TABLE t1(col1 INT, col2 INT); SELECT create_distributed_table('t1', 'col1'); create_distributed_table --------------------------------------------------------------------- (1 row) INSERT INTO t1 SELECT i, i FROM generate_series(1,10) i; CREATE TABLE t2(col1 INT, col2 INT); SELECT create_distributed_table('t2', 'col2'); create_distributed_table --------------------------------------------------------------------- (1 row) INSERT INTO t2 SELECT i, i FROM generate_series(6,15) i; CREATE TABLE t3(col1 INT, col2 INT); SELECT create_distributed_table('t3', 'col1'); create_distributed_table --------------------------------------------------------------------- (1 row) INSERT INTO t3 SELECT i, i FROM generate_series(11,20) i; SET citus.enable_repartition_joins TO ON; SET citus.log_multi_join_order TO ON; SET client_min_messages TO LOG; -- join order planner can handle left outer join between tables with simple join clause -- outer table restricted on partition column whereas inner one is not restricted on the partition column SELECT t1.*, t2.* FROM t1 LEFT JOIN t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; LOG: join order: [ "t1" ][ dual partition join(LEFT) "t2" ] col1 | col2 | col1 | col2 --------------------------------------------------------------------- 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 | | 5 | 5 | | 6 | 6 | 6 | 6 7 | 7 | 7 | 7 8 | 8 | 8 | 8 9 | 9 | 9 | 9 10 | 10 | 10 | 10 (10 rows) -- inner table restricted on partition column whereas outer one is not restricted on the partition column SELECT t1.*, t2.* FROM t1 LEFT JOIN t2 ON (t1.col2 = t2.col2) ORDER BY 1,2,3,4; LOG: join order: [ "t1" ][ dual partition join(LEFT) "t2" ] col1 | col2 | col1 | col2 --------------------------------------------------------------------- 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 | | 5 | 5 | | 6 | 6 | 6 | 6 7 | 7 | 7 | 7 8 | 8 | 8 | 8 9 | 9 | 9 | 9 10 | 10 | 10 | 10 (10 rows) -- both tables are not restricted on partition column SELECT t1.*, t2.* FROM t1 LEFT JOIN t2 ON (t1.col2 = t2.col1) ORDER BY 1,2,3,4; LOG: join order: [ "t1" ][ dual partition join(LEFT) "t2" ] col1 | col2 | col1 | col2 --------------------------------------------------------------------- 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 | | 5 | 5 | | 6 | 6 | 6 | 6 7 | 7 | 7 | 7 8 | 8 | 8 | 8 9 | 9 | 9 | 9 10 | 10 | 10 | 10 (10 rows) -- join order planner can handle right outer join between tables with simple join clause -- outer table restricted on partition column whereas inner one is not restricted on the partition column SELECT t1.*, t2.* FROM t1 RIGHT JOIN t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; LOG: join order: [ "t2" ][ dual partition join(LEFT) "t1" ] col1 | col2 | col1 | col2 --------------------------------------------------------------------- 6 | 6 | 6 | 6 7 | 7 | 7 | 7 8 | 8 | 8 | 8 9 | 9 | 9 | 9 10 | 10 | 10 | 10 | | 11 | 11 | | 12 | 12 | | 13 | 13 | | 14 | 14 | | 15 | 15 (10 rows) -- inner table restricted on partition column whereas outer one is not restricted on the partition column SELECT t1.*, t2.* FROM t1 RIGHT JOIN t2 ON (t1.col2 = t2.col2) ORDER BY 1,2,3,4; LOG: join order: [ "t2" ][ dual partition join(LEFT) "t1" ] col1 | col2 | col1 | col2 --------------------------------------------------------------------- 6 | 6 | 6 | 6 7 | 7 | 7 | 7 8 | 8 | 8 | 8 9 | 9 | 9 | 9 10 | 10 | 10 | 10 | | 11 | 11 | | 12 | 12 | | 13 | 13 | | 14 | 14 | | 15 | 15 (10 rows) -- both tables are not restricted on partition column SELECT t1.*, t2.* FROM t1 RIGHT JOIN t2 ON (t1.col2 = t2.col1) ORDER BY 1,2,3,4; LOG: join order: [ "t2" ][ dual partition join(LEFT) "t1" ] col1 | col2 | col1 | col2 --------------------------------------------------------------------- 6 | 6 | 6 | 6 7 | 7 | 7 | 7 8 | 8 | 8 | 8 9 | 9 | 9 | 9 10 | 10 | 10 | 10 | | 11 | 11 | | 12 | 12 | | 13 | 13 | | 14 | 14 | | 15 | 15 (10 rows) -- join order planner can handle full outer join between tables with simple join clause -- left outer table restricted on partition column whereas right outer one is not restricted on the partition column SELECT t1.*, t2.* FROM t1 FULL JOIN t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; LOG: join order: [ "t1" ][ dual partition join(FULL) "t2" ] col1 | col2 | col1 | col2 --------------------------------------------------------------------- 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 | | 5 | 5 | | 6 | 6 | 6 | 6 7 | 7 | 7 | 7 8 | 8 | 8 | 8 9 | 9 | 9 | 9 10 | 10 | 10 | 10 | | 11 | 11 | | 12 | 12 | | 13 | 13 | | 14 | 14 | | 15 | 15 (15 rows) -- right outer table restricted on partition column whereas left outer one is not restricted on the partition column SELECT t1.*, t2.* FROM t1 FULL JOIN t2 ON (t1.col2 = t2.col2) ORDER BY 1,2,3,4; LOG: join order: [ "t1" ][ dual partition join(FULL) "t2" ] col1 | col2 | col1 | col2 --------------------------------------------------------------------- 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 | | 5 | 5 | | 6 | 6 | 6 | 6 7 | 7 | 7 | 7 8 | 8 | 8 | 8 9 | 9 | 9 | 9 10 | 10 | 10 | 10 | | 11 | 11 | | 12 | 12 | | 13 | 13 | | 14 | 14 | | 15 | 15 (15 rows) -- both tables are not restricted on partition column SELECT t1.*, t2.* FROM t1 FULL JOIN t2 ON (t1.col2 = t2.col1) ORDER BY 1,2,3,4; LOG: join order: [ "t1" ][ dual partition join(FULL) "t2" ] col1 | col2 | col1 | col2 --------------------------------------------------------------------- 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 | | 5 | 5 | | 6 | 6 | 6 | 6 7 | 7 | 7 | 7 8 | 8 | 8 | 8 9 | 9 | 9 | 9 10 | 10 | 10 | 10 | | 11 | 11 | | 12 | 12 | | 13 | 13 | | 14 | 14 | | 15 | 15 (15 rows) -- join order planner can handle queries with multi joins consisting of outer joins with simple join clause SELECT t1.*, t2.*, t3.* FROM t1 RIGHT JOIN t2 ON (t1.col1 = t2.col1) INNER JOIN t3 ON (t3.col1 = t1.col1) ORDER BY 1,2,3,4,5,6; LOG: join order: [ "t1" ][ local partition join(INNER) "t3" ][ dual partition join(INNER) "t2" ] col1 | col2 | col1 | col2 | col1 | col2 --------------------------------------------------------------------- (0 rows) SELECT t1.*, t2.*, t3.* FROM t1 RIGHT JOIN t2 ON (t1.col1 = t2.col1) INNER JOIN t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; LOG: join order: [ "t2" ][ dual partition join(LEFT) "t1" ][ dual partition join(INNER) "t3" ] col1 | col2 | col1 | col2 | col1 | col2 --------------------------------------------------------------------- | | 11 | 11 | 11 | 11 | | 12 | 12 | 12 | 12 | | 13 | 13 | 13 | 13 | | 14 | 14 | 14 | 14 | | 15 | 15 | 15 | 15 (5 rows) SELECT t1.*, t2.*, t3.* FROM t1 RIGHT JOIN t2 ON (t1.col2 = t2.col2) INNER JOIN t3 ON (t3.col2 = t1.col2) ORDER BY 1,2,3,4,5,6; LOG: join order: [ "t1" ][ dual partition join(INNER) "t2" ][ dual partition join(INNER) "t3" ] col1 | col2 | col1 | col2 | col1 | col2 --------------------------------------------------------------------- (0 rows) SELECT t1.*, t2.*, t3.* FROM t1 RIGHT JOIN t2 ON (t1.col2 = t2.col2) INNER JOIN t3 ON (t3.col2 = t2.col2) ORDER BY 1,2,3,4,5,6; LOG: join order: [ "t2" ][ dual partition join(LEFT) "t1" ][ dual partition join(INNER) "t3" ] col1 | col2 | col1 | col2 | col1 | col2 --------------------------------------------------------------------- | | 11 | 11 | 11 | 11 | | 12 | 12 | 12 | 12 | | 13 | 13 | 13 | 13 | | 14 | 14 | 14 | 14 | | 15 | 15 | 15 | 15 (5 rows) SELECT t1.*, t2.*, t3.* FROM t1 RIGHT JOIN t2 ON (t1.col2 = t2.col1) INNER JOIN t3 ON (t3.col2 = t1.col1) ORDER BY 1,2,3,4,5,6; LOG: join order: [ "t1" ][ dual partition join(INNER) "t2" ][ dual partition join(INNER) "t3" ] col1 | col2 | col1 | col2 | col1 | col2 --------------------------------------------------------------------- (0 rows) SELECT t1.*, t2.*, t3.* FROM t1 RIGHT JOIN t2 ON (t1.col2 = t2.col1) INNER JOIN t3 ON (t3.col2 = t2.col1) ORDER BY 1,2,3,4,5,6; LOG: join order: [ "t2" ][ dual partition join(LEFT) "t1" ][ dual partition join(INNER) "t3" ] col1 | col2 | col1 | col2 | col1 | col2 --------------------------------------------------------------------- | | 11 | 11 | 11 | 11 | | 12 | 12 | 12 | 12 | | 13 | 13 | 13 | 13 | | 14 | 14 | 14 | 14 | | 15 | 15 | 15 | 15 (5 rows) SELECT t1.*, t2.*, t3.* FROM t2 LEFT JOIN t1 ON (t1.col1 = t2.col1) INNER JOIN t3 ON (t3.col1 = t1.col1) ORDER BY 1,2,3,4,5,6; LOG: join order: [ "t1" ][ local partition join(INNER) "t3" ][ dual partition join(INNER) "t2" ] col1 | col2 | col1 | col2 | col1 | col2 --------------------------------------------------------------------- (0 rows) SELECT t1.*, t2.*, t3.* FROM t2 LEFT JOIN t1 ON (t1.col1 = t2.col1) INNER JOIN t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; LOG: join order: [ "t2" ][ dual partition join(LEFT) "t1" ][ dual partition join(INNER) "t3" ] col1 | col2 | col1 | col2 | col1 | col2 --------------------------------------------------------------------- | | 11 | 11 | 11 | 11 | | 12 | 12 | 12 | 12 | | 13 | 13 | 13 | 13 | | 14 | 14 | 14 | 14 | | 15 | 15 | 15 | 15 (5 rows) SELECT t1.*, t2.*, t3.* FROM t2 LEFT JOIN t1 ON (t1.col2 = t2.col2) INNER JOIN t3 ON (t3.col2 = t1.col2) ORDER BY 1,2,3,4,5,6; LOG: join order: [ "t2" ][ dual partition join(INNER) "t1" ][ dual partition join(INNER) "t3" ] col1 | col2 | col1 | col2 | col1 | col2 --------------------------------------------------------------------- (0 rows) SELECT t1.*, t2.*, t3.* FROM t2 LEFT JOIN t1 ON (t1.col2 = t2.col2) INNER JOIN t3 ON (t3.col2 = t2.col2) ORDER BY 1,2,3,4,5,6; LOG: join order: [ "t2" ][ dual partition join(LEFT) "t1" ][ dual partition join(INNER) "t3" ] col1 | col2 | col1 | col2 | col1 | col2 --------------------------------------------------------------------- | | 11 | 11 | 11 | 11 | | 12 | 12 | 12 | 12 | | 13 | 13 | 13 | 13 | | 14 | 14 | 14 | 14 | | 15 | 15 | 15 | 15 (5 rows) SELECT t1.*, t2.*, t3.* FROM t2 LEFT JOIN t1 ON (t1.col2 = t2.col1) INNER JOIN t3 ON (t3.col2 = t1.col1) ORDER BY 1,2,3,4,5,6; LOG: join order: [ "t2" ][ dual partition join(INNER) "t1" ][ dual partition join(INNER) "t3" ] col1 | col2 | col1 | col2 | col1 | col2 --------------------------------------------------------------------- (0 rows) SELECT t1.*, t2.*, t3.* FROM t2 LEFT JOIN t1 ON (t1.col2 = t2.col1) INNER JOIN t3 ON (t3.col2 = t2.col1) ORDER BY 1,2,3,4,5,6; LOG: join order: [ "t2" ][ dual partition join(LEFT) "t1" ][ dual partition join(INNER) "t3" ] col1 | col2 | col1 | col2 | col1 | col2 --------------------------------------------------------------------- | | 11 | 11 | 11 | 11 | | 12 | 12 | 12 | 12 | | 13 | 13 | 13 | 13 | | 14 | 14 | 14 | 14 | | 15 | 15 | 15 | 15 (5 rows) SELECT t1.*, t2.*, t3.* FROM t1 FULL JOIN t2 ON (t1.col1 = t2.col1) INNER JOIN t3 ON (t3.col1 = t1.col1) ORDER BY 1,2,3,4,5,6; LOG: join order: [ "t1" ][ dual partition join(LEFT) "t2" ][ dual partition join(INNER) "t3" ] col1 | col2 | col1 | col2 | col1 | col2 --------------------------------------------------------------------- (0 rows) SELECT t1.*, t2.*, t3.* FROM t1 FULL JOIN t2 ON (t1.col1 = t2.col1) INNER JOIN t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; LOG: join order: [ "t2" ][ dual partition join(LEFT) "t1" ][ dual partition join(INNER) "t3" ] col1 | col2 | col1 | col2 | col1 | col2 --------------------------------------------------------------------- | | 11 | 11 | 11 | 11 | | 12 | 12 | 12 | 12 | | 13 | 13 | 13 | 13 | | 14 | 14 | 14 | 14 | | 15 | 15 | 15 | 15 (5 rows) SELECT t1.*, t2.*, t3.* FROM t1 FULL JOIN t2 ON (t1.col2 = t2.col2) INNER JOIN t3 ON (t3.col2 = t1.col2) ORDER BY 1,2,3,4,5,6; LOG: join order: [ "t1" ][ dual partition join(LEFT) "t2" ][ dual partition join(INNER) "t3" ] col1 | col2 | col1 | col2 | col1 | col2 --------------------------------------------------------------------- (0 rows) SELECT t1.*, t2.*, t3.* FROM t1 FULL JOIN t2 ON (t1.col2 = t2.col2) INNER JOIN t3 ON (t3.col2 = t2.col2) ORDER BY 1,2,3,4,5,6; LOG: join order: [ "t2" ][ dual partition join(LEFT) "t1" ][ dual partition join(INNER) "t3" ] col1 | col2 | col1 | col2 | col1 | col2 --------------------------------------------------------------------- | | 11 | 11 | 11 | 11 | | 12 | 12 | 12 | 12 | | 13 | 13 | 13 | 13 | | 14 | 14 | 14 | 14 | | 15 | 15 | 15 | 15 (5 rows) SELECT t1.*, t2.*, t3.* FROM t1 FULL JOIN t2 ON (t1.col2 = t2.col1) INNER JOIN t3 ON (t3.col2 = t1.col1) ORDER BY 1,2,3,4,5,6; LOG: join order: [ "t1" ][ dual partition join(LEFT) "t2" ][ dual partition join(INNER) "t3" ] col1 | col2 | col1 | col2 | col1 | col2 --------------------------------------------------------------------- (0 rows) SELECT t1.*, t2.*, t3.* FROM t1 FULL JOIN t2 ON (t1.col2 = t2.col1) INNER JOIN t3 ON (t3.col2 = t2.col1) ORDER BY 1,2,3,4,5,6; LOG: join order: [ "t2" ][ dual partition join(LEFT) "t1" ][ dual partition join(INNER) "t3" ] col1 | col2 | col1 | col2 | col1 | col2 --------------------------------------------------------------------- | | 11 | 11 | 11 | 11 | | 12 | 12 | 12 | 12 | | 13 | 13 | 13 | 13 | | 14 | 14 | 14 | 14 | | 15 | 15 | 15 | 15 (5 rows) -- join order planner cannot handle semi joins SELECT t1.* FROM t1 WHERE EXISTS (SELECT * FROM t2 WHERE t1.col1 = t2.col1) ORDER BY 1,2; ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns SELECT t1.* FROM t1 WHERE EXISTS (SELECT * FROM t2 WHERE t1.col2 = t2.col2) ORDER BY 1,2; ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns SELECT t2.* FROM t2 WHERE EXISTS (SELECT * FROM t1 WHERE t1.col1 = t2.col1) ORDER BY 1,2; ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns SELECT t2.* FROM t2 WHERE EXISTS (SELECT * FROM t1 WHERE t1.col2 = t2.col2) ORDER BY 1,2; ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns ------------------------- wrong results below, should not be supported if there exists nonsimple join clause -- join order planner cannot handle anti join between tables with simple join clause SELECT t1.* FROM t1 WHERE NOT EXISTS (SELECT * FROM t2 WHERE t1.col1 = t2.col1) ORDER BY 1,2; ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns SELECT t1.* FROM t1 WHERE NOT EXISTS (SELECT * FROM t2 WHERE t1.col2 = t2.col2) ORDER BY 1,2; ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns SELECT t2.* FROM t2 WHERE NOT EXISTS (SELECT * FROM t1 WHERE t1.col1 = t2.col1) ORDER BY 1,2; ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns SELECT t2.* FROM t2 WHERE NOT EXISTS (SELECT * FROM t1 WHERE t1.col2 = t2.col2) ORDER BY 1,2; ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns -- join order planner cannot handle left outer join between tables with nonsimple join clause -- where constraint(t1.col1 IS NULL or t2.col2 IS NULL) is considered as join constraint SELECT t1.*, t2.* FROM t1 LEFT JOIN t2 ON (t1.col1 = t2.col1) WHERE (t1.col1 IS NULL or t2.col2 IS NULL) ORDER BY 1,2,3,4; LOG: join order: [ "t1" ][ dual partition join(LEFT) "t2" ] col1 | col2 | col1 | col2 --------------------------------------------------------------------- 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 | | 5 | 5 | | 6 | 6 | | 7 | 7 | | 8 | 8 | | 9 | 9 | | 10 | 10 | | (10 rows) -- join constraint(t1.col1 < 0) is considered as where constraint SELECT t1.*, t2.* FROM t1 LEFT JOIN t2 ON (t1.col1 = t2.col1 and t1.col1 < 0) ORDER BY 1,2,3,4; LOG: join order: [ "t1" ][ dual partition join(LEFT) "t2" ] col1 | col2 | col1 | col2 --------------------------------------------------------------------- 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 | | 5 | 5 | | 6 | 6 | 6 | 6 7 | 7 | 7 | 7 8 | 8 | 8 | 8 9 | 9 | 9 | 9 10 | 10 | 10 | 10 (10 rows)