Commit 11cf92f6 authored by Robert Haas's avatar Robert Haas

Rewrite the code that applies scan/join targets to paths.

If the toplevel scan/join target list is parallel-safe, postpone
generating Gather (or Gather Merge) paths until after the toplevel has
been adjusted to return it.  This (correctly) makes queries with
expensive functions in the target list more likely to choose a
parallel plan, since the cost of the plan now reflects the fact that
the evaluation will happen in the workers rather than the leader.
The original complaint about this problem was from Jeff Janes.

If the toplevel scan/join relation is partitioned, recursively apply
the changes to all partitions.  This sometimes allows us to get rid of
Result nodes, because Append is not projection-capable but its
children may be.  It also cleans up what appears to be incorrect SRF
handling from commit e2f1eb0e: the old
code had no knowledge of SRFs for child scan/join rels.

Because we now use create_projection_path() in some cases where we
formerly used apply_projection_to_path(), this changes the ordering
of columns in some queries generated by postgres_fdw.  Update
regression outputs accordingly.

Patch by me, reviewed by Amit Kapila and by Ashutosh Bapat.  Other
fixes for this problem (substantially different from this version)
were reviewed by Dilip Kumar, Amit Khandekar, and Marina Polyakova.

Discussion: http://postgr.es/m/CAMkU=1ycXNipvhWuweUVpKuyu6SpNjF=yHWu4c4US5JgVGxtZQ@mail.gmail.com
parent 3f90ec85
......@@ -1030,7 +1030,7 @@ SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t
-> Foreign Scan
Output: t1.c1, t2.c1, t1.c3
Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
Remote SQL: SELECT r1."C 1", r1.c3, r2."C 1" FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST
Remote SQL: SELECT r1."C 1", r2."C 1", r1.c3 FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST
(6 rows)
SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10;
......@@ -1061,7 +1061,7 @@ SELECT t1.c1, t2.c2, t3.c3 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) JOIN ft4 t
-> Foreign Scan
Output: t1.c1, t2.c2, t3.c3, t1.c3
Relations: ((public.ft1 t1) INNER JOIN (public.ft2 t2)) INNER JOIN (public.ft4 t3)
Remote SQL: SELECT r1."C 1", r1.c3, r2.c2, r4.c3 FROM (("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) INNER JOIN "S 1"."T 3" r4 ON (((r1."C 1" = r4.c1))))
Remote SQL: SELECT r1."C 1", r2.c2, r4.c3, r1.c3 FROM (("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) INNER JOIN "S 1"."T 3" r4 ON (((r1."C 1" = r4.c1))))
(9 rows)
SELECT t1.c1, t2.c2, t3.c3 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) JOIN ft4 t3 ON (t3.c1 = t1.c1) ORDER BY t1.c3, t1.c1 OFFSET 10 LIMIT 10;
......@@ -1190,7 +1190,7 @@ SELECT t1.c1, t2.c1 FROM ft5 t1 RIGHT JOIN ft4 t2 ON (t1.c1 = t2.c1) ORDER BY t2
-> Foreign Scan
Output: t1.c1, t2.c1
Relations: (public.ft4 t2) LEFT JOIN (public.ft5 t1)
Remote SQL: SELECT r2.c1, r1.c1 FROM ("S 1"."T 3" r2 LEFT JOIN "S 1"."T 4" r1 ON (((r1.c1 = r2.c1)))) ORDER BY r2.c1 ASC NULLS LAST, r1.c1 ASC NULLS LAST
Remote SQL: SELECT r1.c1, r2.c1 FROM ("S 1"."T 3" r2 LEFT JOIN "S 1"."T 4" r1 ON (((r1.c1 = r2.c1)))) ORDER BY r2.c1 ASC NULLS LAST, r1.c1 ASC NULLS LAST
(6 rows)
SELECT t1.c1, t2.c1 FROM ft5 t1 RIGHT JOIN ft4 t2 ON (t1.c1 = t2.c1) ORDER BY t2.c1, t1.c1 OFFSET 10 LIMIT 10;
......@@ -1218,7 +1218,7 @@ SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 RIGHT JOIN ft2 t2 ON (t1.c1 = t2.c1) RIGH
-> Foreign Scan
Output: t1.c1, t2.c2, t3.c3
Relations: ((public.ft4 t3) LEFT JOIN (public.ft2 t2)) LEFT JOIN (public.ft2 t1)
Remote SQL: SELECT r4.c3, r2.c2, r1."C 1" FROM (("S 1"."T 3" r4 LEFT JOIN "S 1"."T 1" r2 ON (((r2."C 1" = r4.c1)))) LEFT JOIN "S 1"."T 1" r1 ON (((r1."C 1" = r2."C 1"))))
Remote SQL: SELECT r1."C 1", r2.c2, r4.c3 FROM (("S 1"."T 3" r4 LEFT JOIN "S 1"."T 1" r2 ON (((r2."C 1" = r4.c1)))) LEFT JOIN "S 1"."T 1" r1 ON (((r1."C 1" = r2."C 1"))))
(6 rows)
SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 RIGHT JOIN ft2 t2 ON (t1.c1 = t2.c1) RIGHT JOIN ft4 t3 ON (t2.c1 = t3.c1) OFFSET 10 LIMIT 10;
......@@ -1477,7 +1477,7 @@ SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 FULL JOIN ft2 t2 ON (t1.c1 = t2.c1) RIGHT
-> Foreign Scan
Output: t1.c1, t2.c2, t3.c3
Relations: ((public.ft4 t3) LEFT JOIN (public.ft2 t2)) LEFT JOIN (public.ft2 t1)
Remote SQL: SELECT r4.c3, r2.c2, r1."C 1" FROM (("S 1"."T 3" r4 LEFT JOIN "S 1"."T 1" r2 ON (((r2."C 1" = r4.c1)))) LEFT JOIN "S 1"."T 1" r1 ON (((r1."C 1" = r2."C 1"))))
Remote SQL: SELECT r1."C 1", r2.c2, r4.c3 FROM (("S 1"."T 3" r4 LEFT JOIN "S 1"."T 1" r2 ON (((r2."C 1" = r4.c1)))) LEFT JOIN "S 1"."T 1" r1 ON (((r1."C 1" = r2."C 1"))))
(6 rows)
SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 FULL JOIN ft2 t2 ON (t1.c1 = t2.c1) RIGHT JOIN ft4 t3 ON (t2.c1 = t3.c1) OFFSET 10 LIMIT 10;
......@@ -1505,7 +1505,7 @@ SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 RIGHT JOIN ft2 t2 ON (t1.c1 = t2.c1) FULL
-> Foreign Scan
Output: t1.c1, t2.c2, t3.c3
Relations: ((public.ft2 t2) LEFT JOIN (public.ft2 t1)) FULL JOIN (public.ft4 t3)
Remote SQL: SELECT r2.c2, r1."C 1", r4.c3 FROM (("S 1"."T 1" r2 LEFT JOIN "S 1"."T 1" r1 ON (((r1."C 1" = r2."C 1")))) FULL JOIN "S 1"."T 3" r4 ON (((r2."C 1" = r4.c1))))
Remote SQL: SELECT r1."C 1", r2.c2, r4.c3 FROM (("S 1"."T 1" r2 LEFT JOIN "S 1"."T 1" r1 ON (((r1."C 1" = r2."C 1")))) FULL JOIN "S 1"."T 3" r4 ON (((r2."C 1" = r4.c1))))
(6 rows)
SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 RIGHT JOIN ft2 t2 ON (t1.c1 = t2.c1) FULL JOIN ft4 t3 ON (t2.c1 = t3.c1) OFFSET 10 LIMIT 10;
......@@ -1589,7 +1589,7 @@ SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 RIGHT JOIN ft2 t2 ON (t1.c1 = t2.c1) LEFT
-> Foreign Scan
Output: t1.c1, t2.c2, t3.c3
Relations: ((public.ft2 t2) LEFT JOIN (public.ft2 t1)) LEFT JOIN (public.ft4 t3)
Remote SQL: SELECT r2.c2, r1."C 1", r4.c3 FROM (("S 1"."T 1" r2 LEFT JOIN "S 1"."T 1" r1 ON (((r1."C 1" = r2."C 1")))) LEFT JOIN "S 1"."T 3" r4 ON (((r2."C 1" = r4.c1))))
Remote SQL: SELECT r1."C 1", r2.c2, r4.c3 FROM (("S 1"."T 1" r2 LEFT JOIN "S 1"."T 1" r1 ON (((r1."C 1" = r2."C 1")))) LEFT JOIN "S 1"."T 3" r4 ON (((r2."C 1" = r4.c1))))
(6 rows)
SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 RIGHT JOIN ft2 t2 ON (t1.c1 = t2.c1) LEFT JOIN ft4 t3 ON (t2.c1 = t3.c1) OFFSET 10 LIMIT 10;
......@@ -1617,7 +1617,7 @@ SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 LEFT JOIN ft2 t2 ON (t1.c1 = t2.c1) RIGHT
-> Foreign Scan
Output: t1.c1, t2.c2, t3.c3
Relations: (public.ft4 t3) LEFT JOIN ((public.ft2 t1) INNER JOIN (public.ft2 t2))
Remote SQL: SELECT r4.c3, r1."C 1", r2.c2 FROM ("S 1"."T 3" r4 LEFT JOIN ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ON (((r2."C 1" = r4.c1))))
Remote SQL: SELECT r1."C 1", r2.c2, r4.c3 FROM ("S 1"."T 3" r4 LEFT JOIN ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ON (((r2."C 1" = r4.c1))))
(6 rows)
SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 LEFT JOIN ft2 t2 ON (t1.c1 = t2.c1) RIGHT JOIN ft4 t3 ON (t2.c1 = t3.c1) OFFSET 10 LIMIT 10;
......@@ -1676,7 +1676,7 @@ SELECT t1.c1, t2.c2, t1.c3 FROM ft1 t1 FULL JOIN ft2 t2 ON (t1.c1 = t2.c1) WHERE
-> Foreign Scan
Output: t1.c1, t2.c2, t1.c3
Relations: (public.ft1 t1) FULL JOIN (public.ft2 t2)
Remote SQL: SELECT r1."C 1", r1.c3, r2.c2 FROM ("S 1"."T 1" r1 FULL JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) WHERE ((public.postgres_fdw_abs(r1."C 1") > 0))
Remote SQL: SELECT r1."C 1", r2.c2, r1.c3 FROM ("S 1"."T 1" r1 FULL JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) WHERE ((public.postgres_fdw_abs(r1."C 1") > 0))
(6 rows)
ALTER SERVER loopback OPTIONS (DROP extensions);
......@@ -1691,7 +1691,7 @@ SELECT t1.c1, t2.c2, t1.c3 FROM ft1 t1 FULL JOIN ft2 t2 ON (t1.c1 = t2.c1) WHERE
Output: t1.c1, t2.c2, t1.c3
Filter: (postgres_fdw_abs(t1.c1) > 0)
Relations: (public.ft1 t1) FULL JOIN (public.ft2 t2)
Remote SQL: SELECT r1."C 1", r1.c3, r2.c2 FROM ("S 1"."T 1" r1 FULL JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1"))))
Remote SQL: SELECT r1."C 1", r2.c2, r1.c3 FROM ("S 1"."T 1" r1 FULL JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1"))))
(7 rows)
ALTER SERVER loopback OPTIONS (ADD extensions 'postgres_fdw');
......@@ -1708,10 +1708,10 @@ SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t
-> Foreign Scan
Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
Remote SQL: SELECT r1."C 1", r1.c3, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, r2."C 1", CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST FOR UPDATE OF r1
Remote SQL: SELECT r1."C 1", r2."C 1", r1.c3, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST FOR UPDATE OF r1
-> Sort
Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
Sort Key: t1.c3, t1.c1
Sort Key: t1.c3 USING <, t1.c1
-> Merge Join
Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
Merge Cond: (t1.c1 = t2.c1)
......@@ -1755,10 +1755,10 @@ SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t
-> Foreign Scan
Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
Remote SQL: SELECT r1."C 1", r1.c3, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, r2."C 1", CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST FOR UPDATE OF r1 FOR UPDATE OF r2
Remote SQL: SELECT r1."C 1", r2."C 1", r1.c3, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST FOR UPDATE OF r1 FOR UPDATE OF r2
-> Sort
Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
Sort Key: t1.c3, t1.c1
Sort Key: t1.c3 USING <, t1.c1
-> Merge Join
Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
Merge Cond: (t1.c1 = t2.c1)
......@@ -1803,10 +1803,10 @@ SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t
-> Foreign Scan
Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
Remote SQL: SELECT r1."C 1", r1.c3, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, r2."C 1", CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST FOR SHARE OF r1
Remote SQL: SELECT r1."C 1", r2."C 1", r1.c3, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST FOR SHARE OF r1
-> Sort
Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
Sort Key: t1.c3, t1.c1
Sort Key: t1.c3 USING <, t1.c1
-> Merge Join
Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
Merge Cond: (t1.c1 = t2.c1)
......@@ -1850,10 +1850,10 @@ SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t
-> Foreign Scan
Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
Remote SQL: SELECT r1."C 1", r1.c3, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, r2."C 1", CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST FOR SHARE OF r1 FOR SHARE OF r2
Remote SQL: SELECT r1."C 1", r2."C 1", r1.c3, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST FOR SHARE OF r1 FOR SHARE OF r2
-> Sort
Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
Sort Key: t1.c3, t1.c1
Sort Key: t1.c3 USING <, t1.c1
-> Merge Join
Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
Merge Cond: (t1.c1 = t2.c1)
......@@ -1930,7 +1930,7 @@ SELECT t1.ctid, t1, t2, t1.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER B
-> Foreign Scan
Output: t1.ctid, t1.*, t2.*, t1.c1, t1.c3
Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
Remote SQL: SELECT r1.ctid, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, r1."C 1", r1.c3, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST
Remote SQL: SELECT r1.ctid, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END, r1."C 1", r1.c3 FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST
(6 rows)
-- SEMI JOIN, not pushed down
......@@ -2160,7 +2160,7 @@ SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) WHERE t1.c8 = t2.
Output: t1.c1, t2.c1, t1.c3
Filter: (t1.c8 = t2.c8)
Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
Remote SQL: SELECT r1."C 1", r1.c3, r2."C 1", r1.c8, r2.c8 FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1"))))
Remote SQL: SELECT r1."C 1", r2."C 1", r1.c3, r1.c8, r2.c8 FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1"))))
(10 rows)
SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) WHERE t1.c8 = t2.c8 ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10;
......@@ -2348,9 +2348,9 @@ SELECT * FROM ft1, ft2, ft4, ft5 WHERE ft1.c1 = ft2.c1 AND ft1.c2 = ft4.c1
-> Foreign Scan
Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft4.c1, ft4.c2, ft4.c3, ft5.c1, ft5.c2, ft5.c3, ft1.*, ft2.*, ft4.*, ft5.*
Relations: (((public.ft1) INNER JOIN (public.ft2)) INNER JOIN (public.ft4)) INNER JOIN (public.ft5)
Remote SQL: SELECT r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END, r3.c1, r3.c2, r3.c3, CASE WHEN (r3.*)::text IS NOT NULL THEN ROW(r3.c1, r3.c2, r3.c3) END, r4.c1, r4.c2, r4.c3, CASE WHEN (r4.*)::text IS NOT NULL THEN ROW(r4.c1, r4.c2, r4.c3) END FROM ((("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")) AND ((r2."C 1" < 100)) AND ((r1."C 1" < 100)))) INNER JOIN "S 1"."T 3" r3 ON (((r1.c2 = r3.c1)))) INNER JOIN "S 1"."T 4" r4 ON (((r1.c2 = r4.c1)))) FOR UPDATE OF r1 FOR UPDATE OF r2 FOR UPDATE OF r3 FOR UPDATE OF r4
Remote SQL: SELECT r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8, r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8, r3.c1, r3.c2, r3.c3, r4.c1, r4.c2, r4.c3, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END, CASE WHEN (r3.*)::text IS NOT NULL THEN ROW(r3.c1, r3.c2, r3.c3) END, CASE WHEN (r4.*)::text IS NOT NULL THEN ROW(r4.c1, r4.c2, r4.c3) END FROM ((("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")) AND ((r2."C 1" < 100)) AND ((r1."C 1" < 100)))) INNER JOIN "S 1"."T 3" r3 ON (((r1.c2 = r3.c1)))) INNER JOIN "S 1"."T 4" r4 ON (((r1.c2 = r4.c1)))) FOR UPDATE OF r1 FOR UPDATE OF r2 FOR UPDATE OF r3 FOR UPDATE OF r4
-> Merge Join
Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft2.*, ft4.c1, ft4.c2, ft4.c3, ft4.*, ft5.c1, ft5.c2, ft5.c3, ft5.*
Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft4.c1, ft4.c2, ft4.c3, ft5.c1, ft5.c2, ft5.c3, ft1.*, ft2.*, ft4.*, ft5.*
Merge Cond: (ft1.c2 = ft5.c1)
-> Merge Join
Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft2.*, ft4.c1, ft4.c2, ft4.c3, ft4.*
......@@ -2815,7 +2815,7 @@ select sum(c1) from ft1 group by c2 having avg(c1 * (random() <= 1)::int) > 100
Group Key: ft1.c2
Filter: (avg((ft1.c1 * ((random() <= '1'::double precision))::integer)) > '100'::numeric)
-> Foreign Scan on public.ft1
Output: c2, c1
Output: c1, c2
Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1"
(10 rows)
......@@ -3039,7 +3039,7 @@ select sum(c1) filter (where (c1 / c1) * random() <= 1) from ft1 group by c2 ord
Output: sum(c1) FILTER (WHERE ((((c1 / c1))::double precision * random()) <= '1'::double precision)), c2
Group Key: ft1.c2
-> Foreign Scan on public.ft1
Output: c2, c1
Output: c1, c2
Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1"
(9 rows)
......@@ -3213,7 +3213,7 @@ select array_agg(c1 order by c1 using operator(public.<^)) from ft2 where c2 = 6
Output: array_agg(c1 ORDER BY c1 USING <^ NULLS LAST), c2
Group Key: ft2.c2
-> Foreign Scan on public.ft2
Output: c2, c1
Output: c1, c2
Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" WHERE (("C 1" < 100)) AND ((c2 = 6))
(6 rows)
......@@ -3259,7 +3259,7 @@ select array_agg(c1 order by c1 using operator(public.<^)) from ft2 where c2 = 6
Output: array_agg(c1 ORDER BY c1 USING <^ NULLS LAST), c2
Group Key: ft2.c2
-> Foreign Scan on public.ft2
Output: c2, c1
Output: c1, c2
Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" WHERE (("C 1" < 100)) AND ((c2 = 6))
(6 rows)
......@@ -7814,23 +7814,22 @@ SELECT t1.a,t1.b FROM fprt1 t1, LATERAL (SELECT t2.a, t2.b FROM fprt2 t2 WHERE t
-- with PHVs, partition-wise join selected but no join pushdown
EXPLAIN (COSTS OFF)
SELECT t1.a, t1.phv, t2.b, t2.phv FROM (SELECT 't1_phv' phv, * FROM fprt1 WHERE a % 25 = 0) t1 FULL JOIN (SELECT 't2_phv' phv, * FROM fprt2 WHERE b % 25 = 0) t2 ON (t1.a = t2.b) ORDER BY t1.a, t2.b;
QUERY PLAN
------------------------------------------------------------
QUERY PLAN
------------------------------------------------------
Sort
Sort Key: ftprt1_p1.a, ftprt2_p1.b
-> Result
-> Append
-> Hash Full Join
Hash Cond: (ftprt1_p1.a = ftprt2_p1.b)
-> Foreign Scan on ftprt1_p1
-> Hash
-> Foreign Scan on ftprt2_p1
-> Hash Full Join
Hash Cond: (ftprt1_p2.a = ftprt2_p2.b)
-> Foreign Scan on ftprt1_p2
-> Hash
-> Foreign Scan on ftprt2_p2
(14 rows)
-> Append
-> Hash Full Join
Hash Cond: (ftprt1_p1.a = ftprt2_p1.b)
-> Foreign Scan on ftprt1_p1
-> Hash
-> Foreign Scan on ftprt2_p1
-> Hash Full Join
Hash Cond: (ftprt1_p2.a = ftprt2_p2.b)
-> Foreign Scan on ftprt1_p2
-> Hash
-> Foreign Scan on ftprt2_p2
(13 rows)
SELECT t1.a, t1.phv, t2.b, t2.phv FROM (SELECT 't1_phv' phv, * FROM fprt1 WHERE a % 25 = 0) t1 FULL JOIN (SELECT 't2_phv' phv, * FROM fprt2 WHERE b % 25 = 0) t2 ON (t1.a = t2.b) ORDER BY t1.a, t2.b;
a | phv | b | phv
......
......@@ -222,9 +222,10 @@ static bool can_partial_agg(PlannerInfo *root,
const AggClauseCosts *agg_costs);
static void apply_scanjoin_target_to_paths(PlannerInfo *root,
RelOptInfo *rel,
PathTarget *scanjoin_target,
List *scanjoin_targets,
List *scanjoin_targets_contain_srfs,
bool scanjoin_target_parallel_safe,
bool modify_in_place);
bool tlist_same_exprs);
static void create_partitionwise_grouping_paths(PlannerInfo *root,
RelOptInfo *input_rel,
RelOptInfo *grouped_rel,
......@@ -1749,6 +1750,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
List *scanjoin_targets;
List *scanjoin_targets_contain_srfs;
bool scanjoin_target_parallel_safe;
bool scanjoin_target_same_exprs;
bool have_grouping;
AggClauseCosts agg_costs;
WindowFuncLists *wflists = NULL;
......@@ -1967,34 +1969,33 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
}
else
{
/* initialize lists, just to keep compiler quiet */
/* initialize lists; for most of these, dummy values are OK */
final_targets = final_targets_contain_srfs = NIL;
sort_input_targets = sort_input_targets_contain_srfs = NIL;
grouping_targets = grouping_targets_contain_srfs = NIL;
scanjoin_targets = scanjoin_targets_contain_srfs = NIL;
scanjoin_targets = list_make1(scanjoin_target);
scanjoin_targets_contain_srfs = NIL;
}
/*
* Generate Gather or Gather Merge paths for the topmost scan/join
* relation. Once that's done, we must re-determine which paths are
* cheapest. (The previously-cheapest path might even have been
* pfree'd!)
* If the final scan/join target is not parallel-safe, we must
* generate Gather paths now, since no partial paths will be generated
* with the final scan/join targetlist. Otherwise, the Gather or
* Gather Merge paths generated within apply_scanjoin_target_to_paths
* will be superior to any we might generate now in that the
* projection will be done in by each participant rather than only in
* the leader.
*/
generate_gather_paths(root, current_rel, false);
set_cheapest(current_rel);
if (!scanjoin_target_parallel_safe)
generate_gather_paths(root, current_rel, false);
/*
* Forcibly apply SRF-free scan/join target to all the Paths for the
* scan/join rel.
*/
apply_scanjoin_target_to_paths(root, current_rel, scanjoin_target,
scanjoin_target_parallel_safe, true);
/* Now fix things up if scan/join target contains SRFs */
if (parse->hasTargetSRFs)
adjust_paths_for_srfs(root, current_rel,
scanjoin_targets,
scanjoin_targets_contain_srfs);
/* Apply scan/join target. */
scanjoin_target_same_exprs = list_length(scanjoin_targets) == 1
&& equal(scanjoin_target->exprs, current_rel->reltarget->exprs);
apply_scanjoin_target_to_paths(root, current_rel, scanjoin_targets,
scanjoin_targets_contain_srfs,
scanjoin_target_parallel_safe,
scanjoin_target_same_exprs);
/*
* Save the various upper-rel PathTargets we just computed into
......@@ -6796,24 +6797,88 @@ can_partial_agg(PlannerInfo *root, const AggClauseCosts *agg_costs)
/*
* apply_scanjoin_target_to_paths
*
* Applies scan/join target to all the Paths for the scan/join rel.
* Adjust the final scan/join relation, and recursively all of its children,
* to generate the final scan/join target. It would be more correct to model
* this as a separate planning step with a new RelOptInfo at the toplevel and
* for each child relation, but doing it this way is noticeably cheaper.
* Maybe that problem can be solved at some point, but for now we do this.
*
* If tlist_same_exprs is true, then the scan/join target to be applied has
* the same expressions as the existing reltarget, so we need only insert the
* appropriate sortgroupref information. By avoiding the creation of
* projection paths we save effort both immediately and at plan creation time.
*/
static void
apply_scanjoin_target_to_paths(PlannerInfo *root,
RelOptInfo *rel,
PathTarget *scanjoin_target,
List *scanjoin_targets,
List *scanjoin_targets_contain_srfs,
bool scanjoin_target_parallel_safe,
bool modify_in_place)
bool tlist_same_exprs)
{
ListCell *lc;
PathTarget *scanjoin_target;
check_stack_depth();
/*
* In principle we should re-run set_cheapest() here to identify the
* cheapest path, but it seems unlikely that adding the same tlist eval
* costs to all the paths would change that, so we don't bother. Instead,
* just assume that the cheapest-startup and cheapest-total paths remain
* so. (There should be no parameterized paths anymore, so we needn't
* worry about updating cheapest_parameterized_paths.)
* If the scan/join target is not parallel-safe, then the new partial
* pathlist is the empty list.
*/
if (!scanjoin_target_parallel_safe)
{
rel->partial_pathlist = NIL;
rel->consider_parallel = false;
}
/*
* Update the reltarget. This may not be strictly necessary in all cases,
* but it is at least necessary when create_append_path() gets called
* below directly or indirectly, since that function uses the reltarget as
* the pathtarget for the resulting path. It seems like a good idea to do
* it unconditionally.
*/
rel->reltarget = llast_node(PathTarget, scanjoin_targets);
/* Special case: handly dummy relations separately. */
if (IS_DUMMY_REL(rel))
{
/*
* Since this is a dummy rel, it's got a single Append path with no
* child paths. Replace it with a new path having the final scan/join
* target. (Note that since Append is not projection-capable, it
* would be bad to handle this using the general purpose code below;
* we'd end up putting a ProjectionPath on top of the existing Append
* node, which would cause this relation to stop appearing to be a
* dummy rel.)
*/
rel->pathlist = list_make1(create_append_path(rel, NIL, NIL, NULL,
0, false, NIL, -1));
rel->partial_pathlist = NIL;
set_cheapest(rel);
Assert(IS_DUMMY_REL(rel));
/*
* Forget about any child relations. There's no point in adjusting
* them and no point in using them for later planning stages (in
* particular, partitionwise aggregate).
*/
rel->nparts = 0;
rel->part_rels = NULL;
rel->boundinfo = NULL;
return;
}
/* Extract SRF-free scan/join target. */
scanjoin_target = linitial_node(PathTarget, scanjoin_targets);
/*
* Adjust each input path. If the tlist exprs are the same, we can just
* inject the sortgroupref information into the existing pathtarget.
* Otherwise, replace each path with a projection path that generates the
* SRF-free scan/join target. This can't change the ordering of paths
* within rel->pathlist, so we just modify the list in place.
*/
foreach(lc, rel->pathlist)
{
......@@ -6822,52 +6887,31 @@ apply_scanjoin_target_to_paths(PlannerInfo *root,
Assert(subpath->param_info == NULL);
/*
* Don't use apply_projection_to_path() when modify_in_place is false,
* because there could be other pointers to these paths, and therefore
* we mustn't modify them in place.
*/
if (modify_in_place)
newpath = apply_projection_to_path(root, rel, subpath,
scanjoin_target);
if (tlist_same_exprs)
subpath->pathtarget->sortgrouprefs =
scanjoin_target->sortgrouprefs;
else
{
newpath = (Path *) create_projection_path(root, rel, subpath,
scanjoin_target);
/* If we had to add a Result, newpath is different from subpath */
if (newpath != subpath)
{
lfirst(lc) = newpath;
if (subpath == rel->cheapest_startup_path)
rel->cheapest_startup_path = newpath;
if (subpath == rel->cheapest_total_path)
rel->cheapest_total_path = newpath;
}
}
/*
* Upper planning steps which make use of the top scan/join rel's partial
* pathlist will expect partial paths for that rel to produce the same
* output as complete paths ... and we just changed the output for the
* complete paths, so we'll need to do the same thing for partial paths.
* But only parallel-safe expressions can be computed by partial paths.
*/
if (rel->partial_pathlist && scanjoin_target_parallel_safe)
/* Same for partial paths. */
foreach(lc, rel->partial_pathlist)
{
/* Apply the scan/join target to each partial path */
foreach(lc, rel->partial_pathlist)
{
Path *subpath = (Path *) lfirst(lc);
Path *newpath;
Path *subpath = (Path *) lfirst(lc);
Path *newpath;
/* Shouldn't have any parameterized paths anymore */
Assert(subpath->param_info == NULL);
/* Shouldn't have any parameterized paths anymore */
Assert(subpath->param_info == NULL);
/*
* Don't use apply_projection_to_path() here, because there could
* be other pointers to these paths, and therefore we mustn't
* modify them in place.
*/
if (tlist_same_exprs)
subpath->pathtarget->sortgrouprefs =
scanjoin_target->sortgrouprefs;
else
{
newpath = (Path *) create_projection_path(root,
rel,
subpath,
......@@ -6875,16 +6919,83 @@ apply_scanjoin_target_to_paths(PlannerInfo *root,
lfirst(lc) = newpath;
}
}
else
/* Now fix things up if scan/join target contains SRFs */
if (root->parse->hasTargetSRFs)
adjust_paths_for_srfs(root, rel,
scanjoin_targets,
scanjoin_targets_contain_srfs);
/*
* If the relation is partitioned, recurseively apply the same changes to
* all partitions and generate new Append paths. Since Append is not
* projection-capable, that might save a separate Result node, and it also
* is important for partitionwise aggregate.
*/
if (rel->part_scheme && rel->part_rels)
{
/*
* In the unfortunate event that scanjoin_target is not parallel-safe,
* we can't apply it to the partial paths; in that case, we'll need to
* forget about the partial paths, which aren't valid input for upper
* planning steps.
*/
rel->partial_pathlist = NIL;
int partition_idx;
List *live_children = NIL;
/* Adjust each partition. */
for (partition_idx = 0; partition_idx < rel->nparts; partition_idx++)
{
RelOptInfo *child_rel = rel->part_rels[partition_idx];
ListCell *lc;
AppendRelInfo **appinfos;
int nappinfos;
List *child_scanjoin_targets = NIL;
/* Translate scan/join targets for this child. */
appinfos = find_appinfos_by_relids(root, child_rel->relids,
&nappinfos);
foreach(lc, scanjoin_targets)
{
PathTarget *target = lfirst_node(PathTarget, lc);
target = copy_pathtarget(target);
target->exprs = (List *)
adjust_appendrel_attrs(root,
(Node *) target->exprs,
nappinfos, appinfos);
child_scanjoin_targets = lappend(child_scanjoin_targets,
target);
}
pfree(appinfos);
/* Recursion does the real work. */
apply_scanjoin_target_to_paths(root, child_rel,
child_scanjoin_targets,
scanjoin_targets_contain_srfs,
scanjoin_target_parallel_safe,
tlist_same_exprs);
/* Save non-dummy children for Append paths. */
if (!IS_DUMMY_REL(child_rel))
live_children = lappend(live_children, child_rel);
}
/* Build new paths for this relation by appending child paths. */
if (live_children != NIL)
add_paths_to_append_rel(root, rel, live_children);
}
/*
* Consider generating Gather or Gather Merge paths. We must only do this
* if the relation is parallel safe, and we don't do it for child rels to
* avoid creating multiple Gather nodes within the same plan. We must do
* this after all paths have been generated and before set_cheapest, since
* one of the generated paths may turn out to be the cheapest one.
*/
if (rel->consider_parallel && !IS_OTHER_REL(rel))
generate_gather_paths(root, rel, false);
/*
* Reassess which paths are the cheapest, now that we've potentially added
* new Gather (or Gather Merge) and/or Append (or MergeAppend) paths to
* this relation.
*/
set_cheapest(rel);
}
/*
......@@ -6931,7 +7042,6 @@ create_partitionwise_grouping_paths(PlannerInfo *root,
PathTarget *child_target = copy_pathtarget(target);
AppendRelInfo **appinfos;
int nappinfos;
PathTarget *scanjoin_target;
GroupPathExtraData child_extra;
RelOptInfo *child_grouped_rel;
RelOptInfo *child_partially_grouped_rel;
......@@ -6988,26 +7098,6 @@ create_partitionwise_grouping_paths(PlannerInfo *root,
continue;
}
/*
* Copy pathtarget from underneath scan/join as we are modifying it
* and translate its Vars with respect to this appendrel. The input
* relation's reltarget might not be the final scanjoin_target, but
* the pathtarget any given individual path should be.
*/
scanjoin_target =
copy_pathtarget(input_rel->cheapest_startup_path->pathtarget);
scanjoin_target->exprs = (List *)
adjust_appendrel_attrs(root,
(Node *) scanjoin_target->exprs,
nappinfos, appinfos);
/*
* Forcibly apply scan/join target to all the Paths for the scan/join
* rel.
*/
apply_scanjoin_target_to_paths(root, child_input_rel, scanjoin_target,
extra->target_parallel_safe, false);
/* Create grouping paths for this child relation. */
create_ordinary_grouping_paths(root, child_input_rel,
child_grouped_rel,
......
......@@ -65,31 +65,30 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b =
-- left outer join, with whole-row reference
EXPLAIN (COSTS OFF)
SELECT t1, t2 FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a, t2.b;
QUERY PLAN
--------------------------------------------------------
QUERY PLAN
--------------------------------------------------
Sort
Sort Key: t1.a, t2.b
-> Result
-> Append
-> Hash Right Join
Hash Cond: (t2.b = t1.a)
-> Seq Scan on prt2_p1 t2
-> Hash
-> Seq Scan on prt1_p1 t1
Filter: (b = 0)
-> Hash Right Join
Hash Cond: (t2_1.b = t1_1.a)
-> Seq Scan on prt2_p2 t2_1
-> Hash
-> Seq Scan on prt1_p2 t1_1
Filter: (b = 0)
-> Hash Right Join
Hash Cond: (t2_2.b = t1_2.a)
-> Seq Scan on prt2_p3 t2_2
-> Hash
-> Seq Scan on prt1_p3 t1_2
Filter: (b = 0)
(22 rows)
-> Append
-> Hash Right Join
Hash Cond: (t2.b = t1.a)
-> Seq Scan on prt2_p1 t2
-> Hash
-> Seq Scan on prt1_p1 t1
Filter: (b = 0)
-> Hash Right Join
Hash Cond: (t2_1.b = t1_1.a)
-> Seq Scan on prt2_p2 t2_1
-> Hash
-> Seq Scan on prt1_p2 t1_1
Filter: (b = 0)
-> Hash Right Join
Hash Cond: (t2_2.b = t1_2.a)
-> Seq Scan on prt2_p3 t2_2
-> Hash
-> Seq Scan on prt1_p3 t1_2
Filter: (b = 0)
(21 rows)
SELECT t1, t2 FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a, t2.b;
t1 | t2
......@@ -111,30 +110,29 @@ SELECT t1, t2 FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER
-- right outer join
EXPLAIN (COSTS OFF)
SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a = 0 ORDER BY t1.a, t2.b;
QUERY PLAN
---------------------------------------------------------------------
QUERY PLAN
---------------------------------------------------------------
Sort
Sort Key: t1.a, t2.b
-> Result
-> Append
-> Hash Right Join
Hash Cond: (t1.a = t2.b)
-> Seq Scan on prt1_p1 t1
-> Hash
-> Seq Scan on prt2_p1 t2
Filter: (a = 0)
-> Hash Right Join
Hash Cond: (t1_1.a = t2_1.b)
-> Seq Scan on prt1_p2 t1_1
-> Hash
-> Seq Scan on prt2_p2 t2_1
Filter: (a = 0)
-> Nested Loop Left Join
-> Seq Scan on prt2_p3 t2_2
-> Append
-> Hash Right Join
Hash Cond: (t1.a = t2.b)
-> Seq Scan on prt1_p1 t1
-> Hash
-> Seq Scan on prt2_p1 t2
Filter: (a = 0)
-> Index Scan using iprt1_p3_a on prt1_p3 t1_2
Index Cond: (a = t2_2.b)
(21 rows)
-> Hash Right Join
Hash Cond: (t1_1.a = t2_1.b)
-> Seq Scan on prt1_p2 t1_1
-> Hash
-> Seq Scan on prt2_p2 t2_1
Filter: (a = 0)
-> Nested Loop Left Join
-> Seq Scan on prt2_p3 t2_2
Filter: (a = 0)
-> Index Scan using iprt1_p3_a on prt1_p3 t1_2
Index Cond: (a = t2_2.b)
(20 rows)
SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a = 0 ORDER BY t1.a, t2.b;
a | c | b | c
......@@ -375,37 +373,36 @@ EXPLAIN (COSTS OFF)
SELECT * FROM prt1 t1 LEFT JOIN LATERAL
(SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.b) FROM prt1 t2 JOIN prt2 t3 ON (t2.a = t3.b)) ss
ON t1.a = ss.t2a WHERE t1.b = 0 ORDER BY t1.a;
QUERY PLAN
--------------------------------------------------------------------------------
QUERY PLAN
--------------------------------------------------------------------------
Sort
Sort Key: t1.a
-> Result
-> Append
-> Nested Loop Left Join
-> Seq Scan on prt1_p1 t1
Filter: (b = 0)
-> Nested Loop
-> Index Only Scan using iprt1_p1_a on prt1_p1 t2
Index Cond: (a = t1.a)
-> Index Scan using iprt2_p1_b on prt2_p1 t3
Index Cond: (b = t2.a)
-> Nested Loop Left Join
-> Seq Scan on prt1_p2 t1_1
Filter: (b = 0)
-> Nested Loop
-> Index Only Scan using iprt1_p2_a on prt1_p2 t2_1
Index Cond: (a = t1_1.a)
-> Index Scan using iprt2_p2_b on prt2_p2 t3_1
Index Cond: (b = t2_1.a)
-> Nested Loop Left Join
-> Seq Scan on prt1_p3 t1_2
Filter: (b = 0)
-> Nested Loop
-> Index Only Scan using iprt1_p3_a on prt1_p3 t2_2
Index Cond: (a = t1_2.a)
-> Index Scan using iprt2_p3_b on prt2_p3 t3_2
Index Cond: (b = t2_2.a)
(28 rows)
-> Append
-> Nested Loop Left Join
-> Seq Scan on prt1_p1 t1
Filter: (b = 0)
-> Nested Loop
-> Index Only Scan using iprt1_p1_a on prt1_p1 t2
Index Cond: (a = t1.a)
-> Index Scan using iprt2_p1_b on prt2_p1 t3
Index Cond: (b = t2.a)
-> Nested Loop Left Join
-> Seq Scan on prt1_p2 t1_1
Filter: (b = 0)
-> Nested Loop
-> Index Only Scan using iprt1_p2_a on prt1_p2 t2_1
Index Cond: (a = t1_1.a)
-> Index Scan using iprt2_p2_b on prt2_p2 t3_1
Index Cond: (b = t2_1.a)
-> Nested Loop Left Join
-> Seq Scan on prt1_p3 t1_2
Filter: (b = 0)
-> Nested Loop
-> Index Only Scan using iprt1_p3_a on prt1_p3 t2_2
Index Cond: (a = t1_2.a)
-> Index Scan using iprt2_p3_b on prt2_p3 t3_2
Index Cond: (b = t2_2.a)
(27 rows)
SELECT * FROM prt1 t1 LEFT JOIN LATERAL
(SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.b) FROM prt1 t2 JOIN prt2 t3 ON (t2.a = t3.b)) ss
......@@ -538,92 +535,90 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_e t1, prt2_e t2 WHERE (t1.a + t1.b)/2 =
--
EXPLAIN (COSTS OFF)
SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM prt1 t1, prt2 t2, prt1_e t3 WHERE t1.a = t2.b AND t1.a = (t3.a + t3.b)/2 AND t1.b = 0 ORDER BY t1.a, t2.b;
QUERY PLAN
---------------------------------------------------------------------------
QUERY PLAN
---------------------------------------------------------------------
Sort
Sort Key: t1.a
-> Result
-> Append
-> Nested Loop
Join Filter: (t1.a = ((t3.a + t3.b) / 2))
-> Hash Join
-> Append
-> Nested Loop
Join Filter: (t1.a = ((t3.a + t3.b) / 2))
-> Hash Join
Hash Cond: (t2.b = t1.a)
-> Seq Scan on prt2_p1 t2
-> Hash
-> Seq Scan on prt1_p1 t1
Filter: (b = 0)
-> Index Scan using iprt1_e_p1_ab2 on prt1_e_p1 t3
Index Cond: (((a + b) / 2) = t2.b)
-> Nested Loop
Join Filter: (t1_1.a = ((t3_1.a + t3_1.b) / 2))
-> Hash Join
Hash Cond: (t2_1.b = t1_1.a)
-> Seq Scan on prt2_p2 t2_1
-> Hash
-> Seq Scan on prt1_p2 t1_1
Filter: (b = 0)
-> Index Scan using iprt1_e_p2_ab2 on prt1_e_p2 t3_1
Index Cond: (((a + b) / 2) = t2_1.b)
-> Nested Loop
Join Filter: (t1_2.a = ((t3_2.a + t3_2.b) / 2))
-> Hash Join
Hash Cond: (t2_2.b = t1_2.a)
-> Seq Scan on prt2_p3 t2_2
-> Hash
-> Seq Scan on prt1_p3 t1_2
Filter: (b = 0)
-> Index Scan using iprt1_e_p3_ab2 on prt1_e_p3 t3_2
Index Cond: (((a + b) / 2) = t2_2.b)
(33 rows)
SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM prt1 t1, prt2 t2, prt1_e t3 WHERE t1.a = t2.b AND t1.a = (t3.a + t3.b)/2 AND t1.b = 0 ORDER BY t1.a, t2.b;
a | c | b | c | ?column? | c
-----+------+-----+------+----------+---
0 | 0000 | 0 | 0000 | 0 | 0
150 | 0150 | 150 | 0150 | 300 | 0
300 | 0300 | 300 | 0300 | 600 | 0
450 | 0450 | 450 | 0450 | 900 | 0
(4 rows)
EXPLAIN (COSTS OFF)
SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) LEFT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t1.b = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
QUERY PLAN
--------------------------------------------------------------
Sort
Sort Key: t1.a, t2.b, ((t3.a + t3.b))
-> Append
-> Hash Right Join
Hash Cond: (((t3.a + t3.b) / 2) = t1.a)
-> Seq Scan on prt1_e_p1 t3
-> Hash
-> Hash Right Join
Hash Cond: (t2.b = t1.a)
-> Seq Scan on prt2_p1 t2
-> Hash
-> Seq Scan on prt1_p1 t1
Filter: (b = 0)
-> Index Scan using iprt1_e_p1_ab2 on prt1_e_p1 t3
Index Cond: (((a + b) / 2) = t2.b)
-> Nested Loop
Join Filter: (t1_1.a = ((t3_1.a + t3_1.b) / 2))
-> Hash Join
-> Hash Right Join
Hash Cond: (((t3_1.a + t3_1.b) / 2) = t1_1.a)
-> Seq Scan on prt1_e_p2 t3_1
-> Hash
-> Hash Right Join
Hash Cond: (t2_1.b = t1_1.a)
-> Seq Scan on prt2_p2 t2_1
-> Hash
-> Seq Scan on prt1_p2 t1_1
Filter: (b = 0)
-> Index Scan using iprt1_e_p2_ab2 on prt1_e_p2 t3_1
Index Cond: (((a + b) / 2) = t2_1.b)
-> Nested Loop
Join Filter: (t1_2.a = ((t3_2.a + t3_2.b) / 2))
-> Hash Join
-> Hash Right Join
Hash Cond: (((t3_2.a + t3_2.b) / 2) = t1_2.a)
-> Seq Scan on prt1_e_p3 t3_2
-> Hash
-> Hash Right Join
Hash Cond: (t2_2.b = t1_2.a)
-> Seq Scan on prt2_p3 t2_2
-> Hash
-> Seq Scan on prt1_p3 t1_2
Filter: (b = 0)
-> Index Scan using iprt1_e_p3_ab2 on prt1_e_p3 t3_2
Index Cond: (((a + b) / 2) = t2_2.b)
(34 rows)
SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM prt1 t1, prt2 t2, prt1_e t3 WHERE t1.a = t2.b AND t1.a = (t3.a + t3.b)/2 AND t1.b = 0 ORDER BY t1.a, t2.b;
a | c | b | c | ?column? | c
-----+------+-----+------+----------+---
0 | 0000 | 0 | 0000 | 0 | 0
150 | 0150 | 150 | 0150 | 300 | 0
300 | 0300 | 300 | 0300 | 600 | 0
450 | 0450 | 450 | 0450 | 900 | 0
(4 rows)
EXPLAIN (COSTS OFF)
SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) LEFT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t1.b = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
QUERY PLAN
--------------------------------------------------------------------
Sort
Sort Key: t1.a, t2.b, ((t3.a + t3.b))
-> Result
-> Append
-> Hash Right Join
Hash Cond: (((t3.a + t3.b) / 2) = t1.a)
-> Seq Scan on prt1_e_p1 t3
-> Hash
-> Hash Right Join
Hash Cond: (t2.b = t1.a)
-> Seq Scan on prt2_p1 t2
-> Hash
-> Seq Scan on prt1_p1 t1
Filter: (b = 0)
-> Hash Right Join
Hash Cond: (((t3_1.a + t3_1.b) / 2) = t1_1.a)
-> Seq Scan on prt1_e_p2 t3_1
-> Hash
-> Hash Right Join
Hash Cond: (t2_1.b = t1_1.a)
-> Seq Scan on prt2_p2 t2_1
-> Hash
-> Seq Scan on prt1_p2 t1_1
Filter: (b = 0)
-> Hash Right Join
Hash Cond: (((t3_2.a + t3_2.b) / 2) = t1_2.a)
-> Seq Scan on prt1_e_p3 t3_2
-> Hash
-> Hash Right Join
Hash Cond: (t2_2.b = t1_2.a)
-> Seq Scan on prt2_p3 t2_2
-> Hash
-> Seq Scan on prt1_p3 t1_2
Filter: (b = 0)
(34 rows)
(33 rows)
SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) LEFT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t1.b = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
a | c | b | c | ?column? | c
......@@ -644,40 +639,39 @@ SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2
EXPLAIN (COSTS OFF)
SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.c = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
QUERY PLAN
-------------------------------------------------------------------------
QUERY PLAN
-------------------------------------------------------------------
Sort
Sort Key: t1.a, t2.b, ((t3.a + t3.b))
-> Result
-> Append
-> Nested Loop Left Join
-> Hash Right Join
Hash Cond: (t1.a = ((t3.a + t3.b) / 2))
-> Seq Scan on prt1_p1 t1
-> Hash
-> Seq Scan on prt1_e_p1 t3
Filter: (c = 0)
-> Index Scan using iprt2_p1_b on prt2_p1 t2
Index Cond: (t1.a = b)
-> Nested Loop Left Join
-> Hash Right Join
Hash Cond: (t1_1.a = ((t3_1.a + t3_1.b) / 2))
-> Seq Scan on prt1_p2 t1_1
-> Hash
-> Seq Scan on prt1_e_p2 t3_1
Filter: (c = 0)
-> Index Scan using iprt2_p2_b on prt2_p2 t2_1
Index Cond: (t1_1.a = b)
-> Nested Loop Left Join
-> Hash Right Join
Hash Cond: (t1_2.a = ((t3_2.a + t3_2.b) / 2))
-> Seq Scan on prt1_p3 t1_2
-> Hash
-> Seq Scan on prt1_e_p3 t3_2
Filter: (c = 0)
-> Index Scan using iprt2_p3_b on prt2_p3 t2_2
Index Cond: (t1_2.a = b)
(31 rows)
-> Append
-> Nested Loop Left Join
-> Hash Right Join
Hash Cond: (t1.a = ((t3.a + t3.b) / 2))
-> Seq Scan on prt1_p1 t1
-> Hash
-> Seq Scan on prt1_e_p1 t3
Filter: (c = 0)
-> Index Scan using iprt2_p1_b on prt2_p1 t2
Index Cond: (t1.a = b)
-> Nested Loop Left Join
-> Hash Right Join
Hash Cond: (t1_1.a = ((t3_1.a + t3_1.b) / 2))
-> Seq Scan on prt1_p2 t1_1
-> Hash
-> Seq Scan on prt1_e_p2 t3_1
Filter: (c = 0)
-> Index Scan using iprt2_p2_b on prt2_p2 t2_1
Index Cond: (t1_1.a = b)
-> Nested Loop Left Join
-> Hash Right Join
Hash Cond: (t1_2.a = ((t3_2.a + t3_2.b) / 2))
-> Seq Scan on prt1_p3 t1_2
-> Hash
-> Seq Scan on prt1_e_p3 t3_2
Filter: (c = 0)
-> Index Scan using iprt2_p3_b on prt2_p3 t2_2
Index Cond: (t1_2.a = b)
(30 rows)
SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.c = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
a | c | b | c | ?column? | c
......@@ -700,52 +694,51 @@ SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2
-- make sure these go to null as expected
EXPLAIN (COSTS OFF)
SELECT t1.a, t1.phv, t2.b, t2.phv, t3.a + t3.b, t3.phv FROM ((SELECT 50 phv, * FROM prt1 WHERE prt1.b = 0) t1 FULL JOIN (SELECT 75 phv, * FROM prt2 WHERE prt2.a = 0) t2 ON (t1.a = t2.b)) FULL JOIN (SELECT 50 phv, * FROM prt1_e WHERE prt1_e.c = 0) t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t1.a = t1.phv OR t2.b = t2.phv OR (t3.a + t3.b)/2 = t3.phv ORDER BY t1.a, t2.b, t3.a + t3.b;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------
QUERY PLAN
----------------------------------------------------------------------------------------------------------------
Sort
Sort Key: prt1_p1.a, prt2_p1.b, ((prt1_e_p1.a + prt1_e_p1.b))
-> Result
-> Append
-> Append
-> Hash Full Join
Hash Cond: (prt1_p1.a = ((prt1_e_p1.a + prt1_e_p1.b) / 2))
Filter: ((prt1_p1.a = (50)) OR (prt2_p1.b = (75)) OR (((prt1_e_p1.a + prt1_e_p1.b) / 2) = (50)))
-> Hash Full Join
Hash Cond: (prt1_p1.a = ((prt1_e_p1.a + prt1_e_p1.b) / 2))
Filter: ((prt1_p1.a = (50)) OR (prt2_p1.b = (75)) OR (((prt1_e_p1.a + prt1_e_p1.b) / 2) = (50)))
-> Hash Full Join
Hash Cond: (prt1_p1.a = prt2_p1.b)
-> Seq Scan on prt1_p1
Filter: (b = 0)
-> Hash
-> Seq Scan on prt2_p1
Filter: (a = 0)
Hash Cond: (prt1_p1.a = prt2_p1.b)
-> Seq Scan on prt1_p1
Filter: (b = 0)
-> Hash
-> Seq Scan on prt1_e_p1
Filter: (c = 0)
-> Seq Scan on prt2_p1
Filter: (a = 0)
-> Hash
-> Seq Scan on prt1_e_p1
Filter: (c = 0)
-> Hash Full Join
Hash Cond: (prt1_p2.a = ((prt1_e_p2.a + prt1_e_p2.b) / 2))
Filter: ((prt1_p2.a = (50)) OR (prt2_p2.b = (75)) OR (((prt1_e_p2.a + prt1_e_p2.b) / 2) = (50)))
-> Hash Full Join
Hash Cond: (prt1_p2.a = ((prt1_e_p2.a + prt1_e_p2.b) / 2))
Filter: ((prt1_p2.a = (50)) OR (prt2_p2.b = (75)) OR (((prt1_e_p2.a + prt1_e_p2.b) / 2) = (50)))
-> Hash Full Join
Hash Cond: (prt1_p2.a = prt2_p2.b)
-> Seq Scan on prt1_p2
Filter: (b = 0)
-> Hash
-> Seq Scan on prt2_p2
Filter: (a = 0)
Hash Cond: (prt1_p2.a = prt2_p2.b)
-> Seq Scan on prt1_p2
Filter: (b = 0)
-> Hash
-> Seq Scan on prt1_e_p2
Filter: (c = 0)
-> Seq Scan on prt2_p2
Filter: (a = 0)
-> Hash
-> Seq Scan on prt1_e_p2
Filter: (c = 0)
-> Hash Full Join
Hash Cond: (prt1_p3.a = ((prt1_e_p3.a + prt1_e_p3.b) / 2))
Filter: ((prt1_p3.a = (50)) OR (prt2_p3.b = (75)) OR (((prt1_e_p3.a + prt1_e_p3.b) / 2) = (50)))
-> Hash Full Join
Hash Cond: (prt1_p3.a = ((prt1_e_p3.a + prt1_e_p3.b) / 2))
Filter: ((prt1_p3.a = (50)) OR (prt2_p3.b = (75)) OR (((prt1_e_p3.a + prt1_e_p3.b) / 2) = (50)))
-> Hash Full Join
Hash Cond: (prt1_p3.a = prt2_p3.b)
-> Seq Scan on prt1_p3
Filter: (b = 0)
-> Hash
-> Seq Scan on prt2_p3
Filter: (a = 0)
Hash Cond: (prt1_p3.a = prt2_p3.b)
-> Seq Scan on prt1_p3
Filter: (b = 0)
-> Hash
-> Seq Scan on prt1_e_p3
Filter: (c = 0)
(43 rows)
-> Seq Scan on prt2_p3
Filter: (a = 0)
-> Hash
-> Seq Scan on prt1_e_p3
Filter: (c = 0)
(42 rows)
SELECT t1.a, t1.phv, t2.b, t2.phv, t3.a + t3.b, t3.phv FROM ((SELECT 50 phv, * FROM prt1 WHERE prt1.b = 0) t1 FULL JOIN (SELECT 75 phv, * FROM prt2 WHERE prt2.a = 0) t2 ON (t1.a = t2.b)) FULL JOIN (SELECT 50 phv, * FROM prt1_e WHERE prt1_e.c = 0) t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t1.a = t1.phv OR t2.b = t2.phv OR (t3.a + t3.b)/2 = t3.phv ORDER BY t1.a, t2.b, t3.a + t3.b;
a | phv | b | phv | ?column? | phv
......@@ -933,61 +926,60 @@ SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1 WHERE t1.b IN (
EXPLAIN (COSTS OFF)
SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.c = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
QUERY PLAN
----------------------------------------------------------------------------------
QUERY PLAN
----------------------------------------------------------------------------
Sort
Sort Key: t1.a, t2.b, ((t3.a + t3.b))
-> Result
-> Append
-> Merge Left Join
Merge Cond: (t1.a = t2.b)
-> Sort
Sort Key: t1.a
-> Merge Left Join
Merge Cond: ((((t3.a + t3.b) / 2)) = t1.a)
-> Sort
Sort Key: (((t3.a + t3.b) / 2))
-> Seq Scan on prt1_e_p1 t3
Filter: (c = 0)
-> Sort
Sort Key: t1.a
-> Seq Scan on prt1_p1 t1
-> Sort
Sort Key: t2.b
-> Seq Scan on prt2_p1 t2
-> Merge Left Join
Merge Cond: (t1_1.a = t2_1.b)
-> Sort
Sort Key: t1_1.a
-> Merge Left Join
Merge Cond: ((((t3_1.a + t3_1.b) / 2)) = t1_1.a)
-> Sort
Sort Key: (((t3_1.a + t3_1.b) / 2))
-> Seq Scan on prt1_e_p2 t3_1
Filter: (c = 0)
-> Sort
Sort Key: t1_1.a
-> Seq Scan on prt1_p2 t1_1
-> Sort
Sort Key: t2_1.b
-> Seq Scan on prt2_p2 t2_1
-> Merge Left Join
Merge Cond: (t1_2.a = t2_2.b)
-> Sort
Sort Key: t1_2.a
-> Merge Left Join
Merge Cond: ((((t3_2.a + t3_2.b) / 2)) = t1_2.a)
-> Sort
Sort Key: (((t3_2.a + t3_2.b) / 2))
-> Seq Scan on prt1_e_p3 t3_2
Filter: (c = 0)
-> Sort
Sort Key: t1_2.a
-> Seq Scan on prt1_p3 t1_2
-> Sort
Sort Key: t2_2.b
-> Seq Scan on prt2_p3 t2_2
(52 rows)
-> Append
-> Merge Left Join
Merge Cond: (t1.a = t2.b)
-> Sort
Sort Key: t1.a
-> Merge Left Join
Merge Cond: ((((t3.a + t3.b) / 2)) = t1.a)
-> Sort
Sort Key: (((t3.a + t3.b) / 2))
-> Seq Scan on prt1_e_p1 t3
Filter: (c = 0)
-> Sort
Sort Key: t1.a
-> Seq Scan on prt1_p1 t1
-> Sort
Sort Key: t2.b
-> Seq Scan on prt2_p1 t2
-> Merge Left Join
Merge Cond: (t1_1.a = t2_1.b)
-> Sort
Sort Key: t1_1.a
-> Merge Left Join
Merge Cond: ((((t3_1.a + t3_1.b) / 2)) = t1_1.a)
-> Sort
Sort Key: (((t3_1.a + t3_1.b) / 2))
-> Seq Scan on prt1_e_p2 t3_1
Filter: (c = 0)
-> Sort
Sort Key: t1_1.a
-> Seq Scan on prt1_p2 t1_1
-> Sort
Sort Key: t2_1.b
-> Seq Scan on prt2_p2 t2_1
-> Merge Left Join
Merge Cond: (t1_2.a = t2_2.b)
-> Sort
Sort Key: t1_2.a
-> Merge Left Join
Merge Cond: ((((t3_2.a + t3_2.b) / 2)) = t1_2.a)
-> Sort
Sort Key: (((t3_2.a + t3_2.b) / 2))
-> Seq Scan on prt1_e_p3 t3_2
Filter: (c = 0)
-> Sort
Sort Key: t1_2.a
-> Seq Scan on prt1_p3 t1_2
-> Sort
Sort Key: t2_2.b
-> Seq Scan on prt2_p3 t2_2
(51 rows)
SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.c = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
a | c | b | c | ?column? | c
......@@ -1145,42 +1137,41 @@ ANALYZE plt1_e;
-- test partition matching with N-way join
EXPLAIN (COSTS OFF)
SELECT avg(t1.a), avg(t2.b), avg(t3.a + t3.b), t1.c, t2.c, t3.c FROM plt1 t1, plt2 t2, plt1_e t3 WHERE t1.b = t2.b AND t1.c = t2.c AND ltrim(t3.c, 'A') = t1.c GROUP BY t1.c, t2.c, t3.c ORDER BY t1.c, t2.c, t3.c;
QUERY PLAN
--------------------------------------------------------------------------------------
QUERY PLAN
--------------------------------------------------------------------------------
GroupAggregate
Group Key: t1.c, t2.c, t3.c
-> Sort
Sort Key: t1.c, t3.c
-> Result
-> Append
-> Append
-> Hash Join
Hash Cond: (t1.c = ltrim(t3.c, 'A'::text))
-> Hash Join
Hash Cond: (t1.c = ltrim(t3.c, 'A'::text))
-> Hash Join
Hash Cond: ((t1.b = t2.b) AND (t1.c = t2.c))
-> Seq Scan on plt1_p1 t1
-> Hash
-> Seq Scan on plt2_p1 t2
Hash Cond: ((t1.b = t2.b) AND (t1.c = t2.c))
-> Seq Scan on plt1_p1 t1
-> Hash
-> Seq Scan on plt1_e_p1 t3
-> Seq Scan on plt2_p1 t2
-> Hash
-> Seq Scan on plt1_e_p1 t3
-> Hash Join
Hash Cond: (t1_1.c = ltrim(t3_1.c, 'A'::text))
-> Hash Join
Hash Cond: (t1_1.c = ltrim(t3_1.c, 'A'::text))
-> Hash Join
Hash Cond: ((t1_1.b = t2_1.b) AND (t1_1.c = t2_1.c))
-> Seq Scan on plt1_p2 t1_1
-> Hash
-> Seq Scan on plt2_p2 t2_1
Hash Cond: ((t1_1.b = t2_1.b) AND (t1_1.c = t2_1.c))
-> Seq Scan on plt1_p2 t1_1
-> Hash
-> Seq Scan on plt1_e_p2 t3_1
-> Seq Scan on plt2_p2 t2_1
-> Hash
-> Seq Scan on plt1_e_p2 t3_1
-> Hash Join
Hash Cond: (t1_2.c = ltrim(t3_2.c, 'A'::text))
-> Hash Join
Hash Cond: (t1_2.c = ltrim(t3_2.c, 'A'::text))
-> Hash Join
Hash Cond: ((t1_2.b = t2_2.b) AND (t1_2.c = t2_2.c))
-> Seq Scan on plt1_p3 t1_2
-> Hash
-> Seq Scan on plt2_p3 t2_2
Hash Cond: ((t1_2.b = t2_2.b) AND (t1_2.c = t2_2.c))
-> Seq Scan on plt1_p3 t1_2
-> Hash
-> Seq Scan on plt1_e_p3 t3_2
(33 rows)
-> Seq Scan on plt2_p3 t2_2
-> Hash
-> Seq Scan on plt1_e_p3 t3_2
(32 rows)
SELECT avg(t1.a), avg(t2.b), avg(t3.a + t3.b), t1.c, t2.c, t3.c FROM plt1 t1, plt2 t2, plt1_e t3 WHERE t1.b = t2.b AND t1.c = t2.c AND ltrim(t3.c, 'A') = t1.c GROUP BY t1.c, t2.c, t3.c ORDER BY t1.c, t2.c, t3.c;
avg | avg | avg | c | c | c
......@@ -1290,42 +1281,41 @@ ANALYZE pht1_e;
-- test partition matching with N-way join
EXPLAIN (COSTS OFF)
SELECT avg(t1.a), avg(t2.b), avg(t3.a + t3.b), t1.c, t2.c, t3.c FROM pht1 t1, pht2 t2, pht1_e t3 WHERE t1.b = t2.b AND t1.c = t2.c AND ltrim(t3.c, 'A') = t1.c GROUP BY t1.c, t2.c, t3.c ORDER BY t1.c, t2.c, t3.c;
QUERY PLAN
--------------------------------------------------------------------------------------
QUERY PLAN
--------------------------------------------------------------------------------
GroupAggregate
Group Key: t1.c, t2.c, t3.c
-> Sort
Sort Key: t1.c, t3.c
-> Result
-> Append
-> Append
-> Hash Join
Hash Cond: (t1.c = ltrim(t3.c, 'A'::text))
-> Hash Join
Hash Cond: (t1.c = ltrim(t3.c, 'A'::text))
-> Hash Join
Hash Cond: ((t1.b = t2.b) AND (t1.c = t2.c))
-> Seq Scan on pht1_p1 t1
-> Hash
-> Seq Scan on pht2_p1 t2
Hash Cond: ((t1.b = t2.b) AND (t1.c = t2.c))
-> Seq Scan on pht1_p1 t1
-> Hash
-> Seq Scan on pht1_e_p1 t3
-> Seq Scan on pht2_p1 t2
-> Hash
-> Seq Scan on pht1_e_p1 t3
-> Hash Join
Hash Cond: (t1_1.c = ltrim(t3_1.c, 'A'::text))
-> Hash Join
Hash Cond: (t1_1.c = ltrim(t3_1.c, 'A'::text))
-> Hash Join
Hash Cond: ((t1_1.b = t2_1.b) AND (t1_1.c = t2_1.c))
-> Seq Scan on pht1_p2 t1_1
-> Hash
-> Seq Scan on pht2_p2 t2_1
Hash Cond: ((t1_1.b = t2_1.b) AND (t1_1.c = t2_1.c))
-> Seq Scan on pht1_p2 t1_1
-> Hash
-> Seq Scan on pht1_e_p2 t3_1
-> Seq Scan on pht2_p2 t2_1
-> Hash
-> Seq Scan on pht1_e_p2 t3_1
-> Hash Join
Hash Cond: (t1_2.c = ltrim(t3_2.c, 'A'::text))
-> Hash Join
Hash Cond: (t1_2.c = ltrim(t3_2.c, 'A'::text))
-> Hash Join
Hash Cond: ((t1_2.b = t2_2.b) AND (t1_2.c = t2_2.c))
-> Seq Scan on pht1_p3 t1_2
-> Hash
-> Seq Scan on pht2_p3 t2_2
Hash Cond: ((t1_2.b = t2_2.b) AND (t1_2.c = t2_2.c))
-> Seq Scan on pht1_p3 t1_2
-> Hash
-> Seq Scan on pht1_e_p3 t3_2
(33 rows)
-> Seq Scan on pht2_p3 t2_2
-> Hash
-> Seq Scan on pht1_e_p3 t3_2
(32 rows)
SELECT avg(t1.a), avg(t2.b), avg(t3.a + t3.b), t1.c, t2.c, t3.c FROM pht1 t1, pht2 t2, pht1_e t3 WHERE t1.b = t2.b AND t1.c = t2.c AND ltrim(t3.c, 'A') = t1.c GROUP BY t1.c, t2.c, t3.c ORDER BY t1.c, t2.c, t3.c;
avg | avg | avg | c | c | c
......@@ -1463,40 +1453,39 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 LEFT JOIN prt2_l t2 ON t1.a = t2.b
-- right join
EXPLAIN (COSTS OFF)
SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t2.a = 0 ORDER BY t1.a, t2.b;
QUERY PLAN
------------------------------------------------------------------------------------------
QUERY PLAN
------------------------------------------------------------------------------------
Sort
Sort Key: t1.a, t2.b
-> Result
-> Append
-> Hash Right Join
Hash Cond: ((t1.a = t2.b) AND ((t1.c)::text = (t2.c)::text))
-> Seq Scan on prt1_l_p1 t1
-> Hash
-> Seq Scan on prt2_l_p1 t2
Filter: (a = 0)
-> Hash Right Join
Hash Cond: ((t1_1.a = t2_1.b) AND ((t1_1.c)::text = (t2_1.c)::text))
-> Seq Scan on prt1_l_p2_p1 t1_1
-> Hash
-> Seq Scan on prt2_l_p2_p1 t2_1
Filter: (a = 0)
-> Hash Right Join
Hash Cond: ((t1_2.a = t2_2.b) AND ((t1_2.c)::text = (t2_2.c)::text))
-> Seq Scan on prt1_l_p2_p2 t1_2
-> Hash
-> Seq Scan on prt2_l_p2_p2 t2_2
Filter: (a = 0)
-> Hash Right Join
Hash Cond: ((t1_3.a = t2_3.b) AND ((t1_3.c)::text = (t2_3.c)::text))
-> Append
-> Hash Right Join
Hash Cond: ((t1.a = t2.b) AND ((t1.c)::text = (t2.c)::text))
-> Seq Scan on prt1_l_p1 t1
-> Hash
-> Seq Scan on prt2_l_p1 t2
Filter: (a = 0)
-> Hash Right Join
Hash Cond: ((t1_1.a = t2_1.b) AND ((t1_1.c)::text = (t2_1.c)::text))
-> Seq Scan on prt1_l_p2_p1 t1_1
-> Hash
-> Seq Scan on prt2_l_p2_p1 t2_1
Filter: (a = 0)
-> Hash Right Join
Hash Cond: ((t1_2.a = t2_2.b) AND ((t1_2.c)::text = (t2_2.c)::text))
-> Seq Scan on prt1_l_p2_p2 t1_2
-> Hash
-> Seq Scan on prt2_l_p2_p2 t2_2
Filter: (a = 0)
-> Hash Right Join
Hash Cond: ((t1_3.a = t2_3.b) AND ((t1_3.c)::text = (t2_3.c)::text))
-> Append
-> Seq Scan on prt1_l_p3_p1 t1_3
-> Seq Scan on prt1_l_p3_p2 t1_4
-> Hash
-> Append
-> Seq Scan on prt1_l_p3_p1 t1_3
-> Seq Scan on prt1_l_p3_p2 t1_4
-> Hash
-> Append
-> Seq Scan on prt2_l_p3_p1 t2_3
Filter: (a = 0)
(31 rows)
-> Seq Scan on prt2_l_p3_p1 t2_3
Filter: (a = 0)
(30 rows)
SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t2.a = 0 ORDER BY t1.a, t2.b;
a | c | b | c
......@@ -1577,55 +1566,54 @@ EXPLAIN (COSTS OFF)
SELECT * FROM prt1_l t1 LEFT JOIN LATERAL
(SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.b AS t3b, least(t1.a,t2.a,t3.b) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
ON t1.a = ss.t2a AND t1.c = ss.t2c WHERE t1.b = 0 ORDER BY t1.a;
QUERY PLAN
-----------------------------------------------------------------------------------------------------
QUERY PLAN
-----------------------------------------------------------------------------------------------
Sort
Sort Key: t1.a
-> Result
-> Append
-> Nested Loop Left Join
-> Seq Scan on prt1_l_p1 t1
Filter: (b = 0)
-> Hash Join
Hash Cond: ((t3.b = t2.a) AND ((t3.c)::text = (t2.c)::text))
-> Seq Scan on prt2_l_p1 t3
-> Hash
-> Seq Scan on prt1_l_p1 t2
Filter: ((t1.a = a) AND ((t1.c)::text = (c)::text))
-> Nested Loop Left Join
-> Seq Scan on prt1_l_p2_p1 t1_1
Filter: (b = 0)
-> Hash Join
Hash Cond: ((t3_1.b = t2_1.a) AND ((t3_1.c)::text = (t2_1.c)::text))
-> Seq Scan on prt2_l_p2_p1 t3_1
-> Hash
-> Seq Scan on prt1_l_p2_p1 t2_1
Filter: ((t1_1.a = a) AND ((t1_1.c)::text = (c)::text))
-> Nested Loop Left Join
-> Seq Scan on prt1_l_p2_p2 t1_2
-> Append
-> Nested Loop Left Join
-> Seq Scan on prt1_l_p1 t1
Filter: (b = 0)
-> Hash Join
Hash Cond: ((t3.b = t2.a) AND ((t3.c)::text = (t2.c)::text))
-> Seq Scan on prt2_l_p1 t3
-> Hash
-> Seq Scan on prt1_l_p1 t2
Filter: ((t1.a = a) AND ((t1.c)::text = (c)::text))
-> Nested Loop Left Join
-> Seq Scan on prt1_l_p2_p1 t1_1
Filter: (b = 0)
-> Hash Join
Hash Cond: ((t3_1.b = t2_1.a) AND ((t3_1.c)::text = (t2_1.c)::text))
-> Seq Scan on prt2_l_p2_p1 t3_1
-> Hash
-> Seq Scan on prt1_l_p2_p1 t2_1
Filter: ((t1_1.a = a) AND ((t1_1.c)::text = (c)::text))
-> Nested Loop Left Join
-> Seq Scan on prt1_l_p2_p2 t1_2
Filter: (b = 0)
-> Hash Join
Hash Cond: ((t3_2.b = t2_2.a) AND ((t3_2.c)::text = (t2_2.c)::text))
-> Seq Scan on prt2_l_p2_p2 t3_2
-> Hash
-> Seq Scan on prt1_l_p2_p2 t2_2
Filter: ((t1_2.a = a) AND ((t1_2.c)::text = (c)::text))
-> Nested Loop Left Join
-> Append
-> Seq Scan on prt1_l_p3_p1 t1_3
Filter: (b = 0)
-> Hash Join
Hash Cond: ((t3_2.b = t2_2.a) AND ((t3_2.c)::text = (t2_2.c)::text))
-> Seq Scan on prt2_l_p2_p2 t3_2
-> Hash
-> Seq Scan on prt1_l_p2_p2 t2_2
Filter: ((t1_2.a = a) AND ((t1_2.c)::text = (c)::text))
-> Nested Loop Left Join
-> Hash Join
Hash Cond: ((t3_3.b = t2_3.a) AND ((t3_3.c)::text = (t2_3.c)::text))
-> Append
-> Seq Scan on prt1_l_p3_p1 t1_3
Filter: (b = 0)
-> Hash Join
Hash Cond: ((t3_3.b = t2_3.a) AND ((t3_3.c)::text = (t2_3.c)::text))
-> Seq Scan on prt2_l_p3_p1 t3_3
-> Seq Scan on prt2_l_p3_p2 t3_4
-> Hash
-> Append
-> Seq Scan on prt2_l_p3_p1 t3_3
-> Seq Scan on prt2_l_p3_p2 t3_4
-> Hash
-> Append
-> Seq Scan on prt1_l_p3_p1 t2_3
Filter: ((t1_3.a = a) AND ((t1_3.c)::text = (c)::text))
-> Seq Scan on prt1_l_p3_p2 t2_4
Filter: ((t1_3.a = a) AND ((t1_3.c)::text = (c)::text))
(46 rows)
-> Seq Scan on prt1_l_p3_p1 t2_3
Filter: ((t1_3.a = a) AND ((t1_3.c)::text = (c)::text))
-> Seq Scan on prt1_l_p3_p2 t2_4
Filter: ((t1_3.a = a) AND ((t1_3.c)::text = (c)::text))
(45 rows)
SELECT * FROM prt1_l t1 LEFT JOIN LATERAL
(SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.b AS t3b, least(t1.a,t2.a,t3.b) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment