blob: 75d0946c1873d9c5780ceecd26a598c6de70f790 [file] [log] [blame]
-- Test Optimizer Join Hints Feature
--
-- Purpose: Test that join hints may be used to coerce certain plan shapes
LOAD 'pg_hint_plan';
DROP SCHEMA IF EXISTS joinhints CASCADE;
CREATE SCHEMA joinhints;
SET search_path=joinhints;
SET optimizer_trace_fallback=on;
-- Setup tables
CREATE TABLE t1(a int, b int);
CREATE TABLE t2(a int, b int);
CREATE TABLE t3(a int, b int);
CREATE TABLE t4(a int, b int);
CREATE TABLE t5(a int, b int);
SET client_min_messages TO log;
SET pg_hint_plan.debug_print TO ON;
-- Replace timestamp while logging with static string
-- start_matchsubs
-- m/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}:[0-9]{6} [A-Z]{3}/
-- s/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}:[0-9]{6} [A-Z]{3}/YYYY-MM-DD HH:MM:SS:MSMSMS TMZ/
-- end_matchsubs
-- Test that join order hint for every tree shape is applied.
--
-- These check that every possible order on 3 relations. There are 12 possible
-- orders:
--
-- T1 T2 T3 => (T1 T2) T3, T1 (T2 T3)
-- T1 T3 T2 => (T1 T3) T2, T1 (T3 T2)
-- T2 T1 T3 => (T2 T1) T3, T2 (T1 T3)
-- T2 T3 T1 => (T2 T3) T1, T2 (T3 T1)
-- T3 T1 T2 => (T3 T1) T2, T3 (T1 T2)
-- T3 T2 T1 => (T3 T2) T1, T3 (T2 T1)
/*+
Leading((t1 (t2 t3)))
*/
EXPLAIN (costs off) SELECT * FROM t1, t2, t3;
/*+
Leading((t1 (t3 t2)))
*/
EXPLAIN (costs off) SELECT * FROM t1, t2, t3;
/*+
Leading(((t2 t3) t1))
*/
EXPLAIN (costs off) SELECT * FROM t1, t2, t3;
/*+
Leading(((t3 t2) t1))
*/
EXPLAIN (costs off) SELECT * FROM t1, t2, t3;
/*+
Leading(((t1 t3) t2))
*/
EXPLAIN (costs off) SELECT * FROM t1, t2, t3;
/*+
Leading(((t3 t1) t2))
*/
EXPLAIN (costs off) SELECT * FROM t1, t2, t3;
/*+
Leading((t2 (t1 t3)))
*/
EXPLAIN (costs off) SELECT * FROM t1, t2, t3;
/*+
Leading((t2 (t3 t1)))
*/
EXPLAIN (costs off) SELECT * FROM t1, t2, t3;
/*+
Leading(((t1 t2) t3))
*/
EXPLAIN (costs off) SELECT * FROM t1, t2, t3;
/*+
Leading(((t2 t1) t3))
*/
EXPLAIN (costs off) SELECT * FROM t1, t2, t3;
/*+
Leading((t3 (t1 t2)))
*/
EXPLAIN (costs off) SELECT * FROM t1, t2, t3;
/*+
Leading((t3 (t2 t1)))
*/
EXPLAIN (costs off) SELECT * FROM t1, t2, t3;
-- Test that join order hint may be applied over non-leaf nodes
--
-- These check that LIMIT, GROUP BY, or CTE queries may be coerced by a plan
-- hint to produce a specific join order.
/*+
Leading((t2 (t1 t3)))
*/
EXPLAIN (costs off) SELECT * FROM t1, t2, (SELECT * FROM t3 LIMIT 42) AS q;
/*+
Leading(((t5 (t4 t3)) (t1 t2)))
*/
EXPLAIN (costs off) SELECT * FROM (SELECT t1.a FROM t1, t2 LIMIT 42) AS q, t3, t4, t5;
/*+
Leading((t1 (t2 t5)))
*/
EXPLAIN (costs off) SELECT * FROM (SELECT * FROM t1, t2, t5 LIMIT 42) q, t4, t3;
/*+
Leading((((t1 t2) t3) t4))
*/
EXPLAIN (COSTS OFF) SELECT * FROM (SELECT t1.a, t2.a FROM t1, t2, t3 GROUP BY t1.a, t2.a) AS q, t4;
/*+
Leading(((((g2_t1 g2_t2) g2_t3) t4) (g1_t1 (g1_t3 g1_t2))))
*/
EXPLAIN (COSTS OFF) SELECT * FROM (SELECT g1_t1.a, g1_t2.a FROM t1 AS g1_t1, t2 AS g1_t2, t3 AS g1_t3 GROUP BY g1_t1.a, g1_t2.a) AS q1,
(SELECT g2_t1.a, g2_t2.a FROM t1 AS g2_t1, t2 AS g2_t2, t3 AS g2_t3 GROUP BY g2_t1.a, g2_t2.a) AS q2, t4, t5;
/*+
Leading(((t3 t2) t1))
Leading((t5 t4))
*/
EXPLAIN (COSTS OFF)
WITH cte AS
(
SELECT * FROM t1, t2, t3
)
SELECT * FROM cte, t4, t5;
-- Test that bad join order hint is *not* applied
--
-- These check that invalid plans are not produced.
-- No plan joins (t2 t3) becase the query has LIMIT on (t1 t2) which must be
-- applied after joining (t1 t2)
/*+
Leading((t1 t3))
*/
EXPLAIN (costs off) SELECT * FROM (SELECT t1.a FROM t1, t2 LIMIT 42) AS q, t3, t4, t5;
-- No plan joins (t2 t3) because the GROUP BY is on (t1 t2)
/*+
Leading((t2 t3))
*/
EXPLAIN (COSTS OFF) SELECT * FROM (SELECT t1.a, t2.a FROM t1, t2 GROUP BY t1.a, t2.a) AS q, t3;
-- syntax error: extra parens
/*+
Leading(((t1 t2)))
*/
EXPLAIN (costs off) SELECT * FROM t1, t2;
-- syntax error: cannot mix directed and non-directed hint
/*+
Leading((t1 (t2 t3 t4)))
*/
EXPLAIN (costs off) SELECT * FROM t1, t2, t3, t4;
-- Cannot partially specify lower join hint if upper join hint specified.
--
-- Lower join on t2, t3, t4 is not fully specified (hint on t3 missing), and
-- upper join on t1, (t2, t3 t4), t5 is partially specified (hint on t1
-- exists).
/*+
Leading(((t1 t5) (t2 t4)))
*/
EXPLAIN (costs off) SELECT * FROM t1, (SELECT * FROM t2, t3, t4 LIMIT 42) AS q, t5;
-- Cannot specify hint between leaf nodes of different joins
--
-- t1 and t3 are leaf nodes of different joins. Hint cannot join them together
-- without first completing join of all relations in one join.
/*+
Leading(((t1 t3) (t2 t4)))
*/
EXPLAIN (costs off) SELECT * FROM t1, (SELECT * FROM t2, t3, t4 LIMIT 42) AS q, t5;
-- Cannot apply two conflicting hints
--
-- One hint specifiese t1 on outer side, but the other hint joins t1 inner
-- side. Both hints cannot be satisfied.
/*+
Leading((t1 t2))
Leading((t2 t1))
*/
EXPLAIN (costs off) SELECT * FROM t1, t2;
/*+
Leading((((t5 t4) (t1 t3)) t2))
*/
EXPLAIN (costs off) SELECT t1.a, t2.a FROM t1, t2, t3, t4, t5;
/*+
Leading(((t5 t4) (t1 t3)))
*/
EXPLAIN (costs off) SELECT t1.a, t2.a FROM t1, t2, t3, t4, t5;
/*+
Leading((t2 t1))
*/
EXPLAIN (costs off) SELECT t1.a, t2.a FROM t1 JOIN t2 ON t1.a=t2.a JOIN t3 ON t3.a=t1.a, t4, t5;
/*+
Leading((t5 (((t4 t3) t2) t1)))
*/
EXPLAIN (costs off) SELECT t1.a, t2.a FROM t1 JOIN t2 ON t1.a=t2.a JOIN t3 ON t3.a=t1.a, t4, t5;
/*+
Leading((t5 (((t4 t3) t2) t1)))
*/
EXPLAIN (costs off) SELECT t1.a, t2.a FROM t1 JOIN t2 ON t1.a=t2.a JOIN t3 ON t3.a=t1.a+1 AND t3.a>42, t4, t5;
-- Test that multiple join order hint can be applied
--
-- Following queries produce multiple NAry join operators where different join
-- order hints may be applied.
/*+
Leading((t3 t4))
Leading((t1 (t2 t5)))
*/
EXPLAIN (costs off) SELECT * FROM t4, t3, (SELECT * FROM t1, t2, t5 LIMIT 42) q;
-- mixes directioned and directioned-less hint syntax
/*+
Leading((t3 t4))
Leading(t1 t2 t5)
*/
EXPLAIN (costs off) SELECT * FROM t4, t3, (SELECT * FROM t1, t2, t5 LIMIT 42) q;
/*+
Leading((t3 t4))
Leading((t1 (t2 t5)))
*/
EXPLAIN (costs off) SELECT * FROM (SELECT * FROM t4, t3 LIMIT 1) p, (SELECT * FROM t1, t2, t5 LIMIT 42) q;
-- Test that directioned-less join order hints can be applied
--
-- Following queries use directioned-less syntax. Example:
--
-- "Leading(t1 t2 ... tn)"
--
-- Above example specifies that t1 JOIN t2 happens *before* JOIN tn. But t1 can
-- be on the inner or outer side of the join. In contrast "Leading((t1 t2))
-- requires t1 to be on the outer side of the join.
/*+
Leading(t1 t2 t3)
*/
EXPLAIN (costs off) SELECT * FROM t1, t2, t3;
/*+
Leading(t3 t2 t1)
*/
EXPLAIN (costs off) SELECT * FROM t1, t2, t3;
--------------------------------------------------------------------
-- Test join type hints can be applied
--
-- Join types can be HashJoin, NestLoop, or MergeJoin
--
-- NOTE: An index-nestloop join is a combination of NestLoop and IndexScan
--------------------------------------------------------------------
CREATE INDEX i1 ON t1(a);
CREATE INDEX i2 ON t2(a);
CREATE INDEX i3 ON t3(a);
CREATE INDEX i4 ON t4(a);
CREATE INDEX i5 ON t5(a);
/*+
HashJoin(t1 t2)
*/
EXPLAIN (costs off) SELECT * FROM t1 JOIN t2 ON t1.a=t2.a;
/*+
NoHashJoin(t1 t2)
*/
EXPLAIN (costs off) SELECT * FROM t1 JOIN t2 ON t1.a=t2.a;
/*+
NestLoop(t1 t2)
SeqScan(t1)
SeqScan(t2)
*/
EXPLAIN (costs off) SELECT * FROM t1 JOIN t2 ON t1.a=t2.a;
/*+
NestLoop(t1 t2)
IndexScan(t1)
*/
EXPLAIN (costs off) SELECT * FROM t1 JOIN t2 ON t1.a=t2.a;
/*+
NestLoop(t1 t2)
IndexScan(t2)
*/
EXPLAIN (costs off) SELECT * FROM t1 JOIN t2 ON t1.a=t2.a;
/*+
NoNestLoop(t1 t2)
*/
EXPLAIN (costs off) SELECT * FROM t1 JOIN t2 ON t1.a=t2.a;
/*+
NoHashJoin(t1 t2 t3)
*/
EXPLAIN (costs off) SELECT * FROM t1 JOIN t2 ON t1.a=t2.a JOIN t3 ON t1.a=t3.a;
/*+
NoHashJoin(t2 t3)
NoHashJoin(t1 t3)
NoHashJoin(t1 t2)
NoHashJoin(t1 t2 t3)
*/
EXPLAIN (costs off) SELECT * FROM t1 JOIN t2 ON t1.a=t2.a JOIN t3 ON t1.a=t3.a;
/*+
NoNestLoop(t1 t2 t3)
*/
EXPLAIN (costs off) SELECT * FROM t1 JOIN t2 ON t1.a=t2.a JOIN t3 ON t1.a=t3.a;
/*+
NoNestLoop(t2 t3)
NoNestLoop(t1 t3)
NoNestLoop(t1 t2)
NoNestLoop(t1 t2 t3)
*/
EXPLAIN (costs off) SELECT * FROM t1 JOIN t2 ON t1.a=t2.a JOIN t3 ON t1.a=t3.a;
--
-- Test nest loop join type hints
--
/*+
NestLoop(t1 t2)
*/
EXPLAIN (COSTS off) SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a;
/*+
NestLoop(t1 t2)
*/
EXPLAIN (COSTS off) SELECT * FROM t1 RIGHT JOIN t2 ON t1.a = t2.a;
-- XXX: ORCA doesn't support nest join on full join
/*+
NestLoop(t1 t2)
*/
EXPLAIN (COSTS off) SELECT * FROM t1 FULL JOIN t2 ON t1.a = t2.a;
/*+
NestLoop(t1 t2)
*/
EXPLAIN (COSTS off) SELECT * FROM t1 WHERE t1.a IN (SELECT t2.a FROM t2);
/*+
NestLoop(t1 t2)
*/
EXPLAIN (COSTS off) SELECT * FROM t1 WHERE t1.a NOT IN (SELECT t2.a FROM t2);
--
-- Test merge join type hints
--
-- XXX: ORCA doesn't support merge join on left join
/*+
MergeJoin(t1 t2)
*/
EXPLAIN (COSTS off) SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a;
-- XXX: ORCA doesn't support merge join on right join
/*+
MergeJoin(t1 t2)
*/
EXPLAIN (COSTS off) SELECT * FROM t1 RIGHT JOIN t2 ON t1.a = t2.a;
/*+
MergeJoin(t1 t2)
*/
EXPLAIN (COSTS off) SELECT * FROM t1 FULL JOIN t2 ON t1.a = t2.a;
-- XXX: ORCA doesn't support merge join on semi-join
/*+
MergeJoin(t1 t2)
*/
EXPLAIN (COSTS off) SELECT * FROM t1 WHERE t1.a IN (SELECT t2.a FROM t2);
-- XXX: ORCA doesn't support merge join on anti-semi-join
/*+
MergeJoin(t1 t2)
*/
EXPLAIN (COSTS off) SELECT * FROM t1 WHERE t1.a NOT IN (SELECT t2.a FROM t2);
--
-- Test hash join type hints
--
/*+
HashJoin(t1 t2)
*/
EXPLAIN (COSTS off) SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a;
/*+
HashJoin(t1 t2)
*/
EXPLAIN (COSTS off) SELECT * FROM t1 RIGHT JOIN t2 ON t1.a = t2.a;
/*+
HashJoin(t1 t2)
*/
EXPLAIN (COSTS off) SELECT * FROM t1 FULL JOIN t2 ON t1.a = t2.a;
/*+
HashJoin(t1 t2)
*/
EXPLAIN (COSTS off) SELECT * FROM t1 WHERE t1.a IN (SELECT t2.a FROM t2);
/*+
HashJoin(t1 t2)
*/
EXPLAIN (COSTS off) SELECT * FROM t1 WHERE t1.a NOT IN (SELECT t2.a FROM t2);
-- Test planhints logging for JoinTypeHints
-- Missing alias in hint to test 'not used' hints logging
/*+
HashJoin(y z)
*/
EXPLAIN (COSTS off) SELECT * FROM t1 WHERE t1.a NOT IN (SELECT t2.a FROM t2);
-- Invalid JoinHint type to test Hint logging behavior
/*+
InvalidJoinTypeHint(t1)
*/
EXPLAIN (COSTS off) SELECT * FROM t1 WHERE t1.a IN (SELECT t2.a FROM t2);
-- Test join order hints on non-inner join queries
--
-- Following queries exercise LOJ and ROJ
/*+
Leading((t1 (t2 t3)))
*/
EXPLAIN (costs off) SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.a=t3.a AND t3.a>40;
/*+
Leading(((t1 t4) (t2 t3)))
*/
EXPLAIN (costs off) SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.a=t3.a LEFT JOIN t4 on t1.a=t4.a;
/*+
Leading(((t3 t2) t1))
*/
EXPLAIN (costs off) SELECT * FROM t1 JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.a=t3.a;
/*+
Leading(((t3 t2) t1))
*/
EXPLAIN (costs off) SELECT * FROM t1, t2 LEFT JOIN t3 ON t2.a=t3.a;
/*+
Leading(((t3 t2) t1))
*/
EXPLAIN (costs off) SELECT * FROM t1, t2 RIGHT JOIN t3 ON t2.a=t3.a;
/*+
Leading((t2 t1))
*/
EXPLAIN (costs off) SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a;
-- Bad LOJ/ROJ hints
--
-- Notice that the join condition does not allow the following hint to be
-- applied. This is because, unlike inner join, the join predicates of LOJ/ROJ
-- are not transitive.
/*+
Leading(((t1 t4) (t2 t3)))
*/
EXPLAIN (costs off) SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.a=t3.a LEFT JOIN t4 on t2.a=t4.a;
-- Again, the join condition does not allow the following hint to be applied.
-- Here t3 join condition requires t1, it is illegal to join t2 and t3 first.
/*+
Leading((t1 (t2 t3)))
*/
EXPLAIN (costs off) SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t1.a=t3.a;
-- Again, the join condition does not allow the following hint to be applied.
-- Here t3 join condition requires t1, it is illegal to join t2 and t3 first.
/*+
Leading((t1 (t2 t3)))
*/
EXPLAIN (costs off) SELECT * FROM t1 RIGHT JOIN t2 ON t1.a=t2.a RIGHT JOIN t3 ON t1.a=t3.a;
-- Make sure we generate the same plan when hints are not used.
EXPLAIN (costs off) SELECT * FROM t1 RIGHT JOIN t2 ON t1.a=t2.a RIGHT JOIN t3 ON t1.a=t3.a;
-- Tables (t2 and t3) of INNER JOIN on the inner side of a LEFT JOIN cannot be
-- reordered with the tables (t1) on the outer side.
/*+
Leading((t1 t2))
*/
EXPLAIN (costs off) SELECT * FROM t1 LEFT JOIN (t2 INNER JOIN t3 ON t2.a = t3.a) ON t1.a = t2.a;
-- Tables (t2 and t3) of INNER JOIN on the outer side of a RIGHT JOIN cannot be
-- reordered with the tables (t1) on the inner side.
/*+
Leading((t1 t2))
*/
EXPLAIN (costs off) SELECT * FROM t2 INNER JOIN t3 ON t2.a = t3.a RIGHT JOIN t1 ON t1.a=t2.a;
-- Test that only *valid* join order hint shapes are applied for LOJ.
--
-- These check that every possible order on 3 relations. There are 12 possible
-- orders:
--
-- T1 T2 T3 => (T1 T2) T3, T1 (T2 T3)
-- T1 T3 T2 => (T1 T3) T2, T1 (T3 T2)
-- T2 T1 T3 => (T2 T1) T3, T2 (T1 T3)
-- T2 T3 T1 => (T2 T3) T1, T2 (T3 T1)
-- T3 T1 T2 => (T3 T1) T2, T3 (T1 T2)
-- T3 T2 T1 => (T3 T2) T1, T3 (T2 T1)
--
-- Note that not every order is a valid plan! And that regardless of the hint,
-- the query should produce the same results.
INSERT INTO t1 VALUES (50, 50), (51, 51), (NULL, NULL);
INSERT INTO t2 VALUES (50, 50), (52, 52), (NULL, NULL);
INSERT INTO t3 VALUES (50, 50), (53, 53), (NULL, NULL);
INSERT INTO t4 VALUES (50, 50), (54, 54), (NULL, NULL);
INSERT INTO t5 VALUES (50, 50), (55, 55), (NULL, NULL);
/*+
Leading((t1 (t2 t3)))
*/
EXPLAIN (costs off)
SELECT * FROM t1 JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t1.a=t3.a;
/*+
Leading((t1 (t2 t3)))
*/
SELECT * FROM t1 JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t1.a=t3.a;
/*+
Leading((t1 (t3 t2)))
*/
EXPLAIN (costs off)
SELECT * FROM t1 JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t1.a=t3.a;
/*+
Leading((t1 (t3 t2)))
*/
SELECT * FROM t1 JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t1.a=t3.a;
/*+
Leading(((t2 t3) t1))
*/
EXPLAIN (costs off)
SELECT * FROM t1 JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t1.a=t3.a;
/*+
Leading(((t2 t3) t1))
*/
SELECT * FROM t1 JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t1.a=t3.a;
/*+
Leading(((t3 t2) t1))
*/
EXPLAIN (costs off)
SELECT * FROM t1 JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t1.a=t3.a;
/*+
Leading(((t3 t2) t1))
*/
SELECT * FROM t1 JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t1.a=t3.a;
/*+
Leading(((t1 t3) t2))
*/
EXPLAIN (costs off)
SELECT * FROM t1 JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t1.a=t3.a;
/*+
Leading(((t1 t3) t2))
*/
SELECT * FROM t1 JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t1.a=t3.a;
/*+
Leading(((t3 t1) t2))
*/
EXPLAIN (costs off)
SELECT * FROM t1 JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t1.a=t3.a;
/*+
Leading(((t3 t1) t2))
*/
SELECT * FROM t1 JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t1.a=t3.a;
/*+
Leading((t2 (t1 t3)))
*/
EXPLAIN (costs off)
SELECT * FROM t1 JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t1.a=t3.a;
/*+
Leading((t2 (t1 t3)))
*/
SELECT * FROM t1 JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t1.a=t3.a;
/*+
Leading((t2 (t3 t1)))
*/
EXPLAIN (costs off)
SELECT * FROM t1 JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t1.a=t3.a;
/*+
Leading((t2 (t3 t1)))
*/
SELECT * FROM t1 JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t1.a=t3.a;
/*+
Leading(((t1 t2) t3))
*/
EXPLAIN (costs off)
SELECT * FROM t1 JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t1.a=t3.a;
/*+
Leading(((t1 t2) t3))
*/
SELECT * FROM t1 JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t1.a=t3.a;
/*+
Leading(((t2 t1) t3))
*/
EXPLAIN (costs off)
SELECT * FROM t1 JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t1.a=t3.a;
/*+
Leading(((t2 t1) t3))
*/
SELECT * FROM t1 JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t1.a=t3.a;
/*+
Leading((t3 (t1 t2)))
*/
EXPLAIN (costs off)
SELECT * FROM t1 JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t1.a=t3.a;
/*+
Leading((t3 (t1 t2)))
*/
SELECT * FROM t1 JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t1.a=t3.a;
/*+
Leading((t3 (t2 t1)))
*/
EXPLAIN (costs off)
SELECT * FROM t1 JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t1.a=t3.a;
/*+
Leading((t3 (t2 t1)))
*/
SELECT * FROM t1 JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t1.a=t3.a;
/*+
Leading((t1 t2))
*/
EXPLAIN (costs off)
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.a=t3.a;
/*+
Leading((t1 t2))
*/
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.a=t3.a;
/*+
Leading((t2 t1))
*/
EXPLAIN (costs off)
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.a=t3.a;
/*+
Leading((t2 t1))
*/
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.a=t3.a;
/*+
Leading((t2 t3))
*/
EXPLAIN (costs off)
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.a=t3.a;
/*+
Leading((t2 t3))
*/
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.a=t3.a;
/*+
Leading((t3 t2))
*/
EXPLAIN (costs off)
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.a=t3.a;
/*+
Leading((t3 t2))
*/
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.a=t3.a;
/*+
Leading((t1 t3))
*/
EXPLAIN (costs off)
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.a=t3.a;
/*+
Leading((t1 t3))
*/
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.a=t3.a;
/*+
Leading((t3 t1))
*/
EXPLAIN (costs off)
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.a=t3.a;
/*+
Leading((t3 t1))
*/
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.a=t3.a;
-- Test LOJ cases where middle joins are applied first
--
-- For example, if query is:
--
-- T1 LOJ T2 LOJ T3 LOJ T4 LOJ T5
--
-- Then if hint is Leading((T2 T3)), then query should generate correct results.
/*+
Leading((t2 t3))
*/
EXPLAIN (costs off)
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.a=t3.a LEFT JOIN t4 ON t3.a=t4.a LEFT JOIN t5 ON t1.a=t5.a;
/*+
Leading((t2 t3))
*/
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.a=t3.a LEFT JOIN t4 ON t3.a=t4.a LEFT JOIN t5 ON t1.a=t5.a;
/*+
Leading((t3 t2))
*/
EXPLAIN (costs off)
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.a=t3.a LEFT JOIN t4 ON t3.a=t4.a LEFT JOIN t5 ON t1.a=t5.a;
/*+
Leading((t3 t2))
*/
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.a=t3.a LEFT JOIN t4 ON t3.a=t4.a LEFT JOIN t5 ON t1.a=t5.a;
/*+
Leading((t4 (t3 t2)))
*/
EXPLAIN (costs off)
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.a=t3.a LEFT JOIN t4 ON t3.a=t4.a LEFT JOIN t5 ON t1.a=t5.a;
/*+
Leading((t4 (t3 t2)))
*/
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a LEFT JOIN t3 ON t2.a=t3.a LEFT JOIN t4 ON t3.a=t4.a LEFT JOIN t5 ON t1.a=t5.a;
-- Test LOJ cases with NULL aware predicates
--
-- Join order cannot be reordered if a join predicate is satisified when the
-- column of a table is NULL. This is because the number of NULLs can change
-- based on the order the join is executed.
--
-- For example,
--
-- Table Data:
-- T1 T2 T3
-- -- -- --
-- 1 NULL 1
--
-- Order #1:
-- (T1 LOJ T2 ON T1.a=T2.a) LOJ T3 ON t2.a IS NULL
-- T1 | T2 |T3
-- ---+----+---
-- 1 | |1
--
-- Order #2:
-- T1 LOJ (T2 LOJ T3 ON t2.a IS NULL) ON T1.a=T2.a
-- T1 | T2 |T3
-- ---+----+---
-- 1 | |
/*+
Leading((t2 t3))
*/
EXPLAIN (costs off)
SELECT * FROM t1 LEFT JOIN t2 ON t2.a>53 LEFT JOIN t3 ON t2.a IS NULL;
/*+
Leading((t2 t3))
*/
SELECT * FROM t1 LEFT JOIN t2 ON t2.a>53 LEFT JOIN t3 ON t2.a IS NULL;
/*+
Leading((t1 t3))
*/
EXPLAIN (costs off)
SELECT * FROM t1 LEFT JOIN t2 ON t2.a>53 LEFT JOIN t3 ON t2.a IS NULL;
/*+
Leading((t1 t3))
*/
SELECT * FROM t1 LEFT JOIN t2 ON t2.a>53 LEFT JOIN t3 ON t2.a IS NULL;
/*+
Leading((t1 t2))
*/
EXPLAIN (costs off)
SELECT * FROM t1 LEFT JOIN t2 ON t2.a>53 LEFT JOIN t3 ON t2.a IS NULL;
/*+
Leading((t1 t2))
*/
SELECT * FROM t1 LEFT JOIN t2 ON t2.a>53 LEFT JOIN t3 ON t2.a IS NULL;
/*+
Leading((t2 t3))
*/
EXPLAIN (costs off)
SELECT * FROM t1 LEFT JOIN t2 ON t2.a>53 LEFT JOIN t3 ON NOT t2.a IS NOT NULL;
/*+
Leading((t2 t3))
*/
SELECT * FROM t1 LEFT JOIN t2 ON t2.a>53 LEFT JOIN t3 ON NOT t2.a IS NOT NULL;
/*+
Leading((t1 t3))
*/
EXPLAIN (costs off)
SELECT * FROM t1 LEFT JOIN t2 ON t2.a>53 LEFT JOIN t3 ON NOT t2.a IS NOT NULL;
/*+
Leading((t1 t3))
*/
SELECT * FROM t1 LEFT JOIN t2 ON t2.a>53 LEFT JOIN t3 ON NOT t2.a IS NOT NULL;
/*+
Leading((t1 t2))
*/
EXPLAIN (costs off)
SELECT * FROM t1 LEFT JOIN t2 ON t2.a>53 LEFT JOIN t3 ON NOT t2.a IS NOT NULL;
/*+
Leading((t1 t2))
*/
SELECT * FROM t1 LEFT JOIN t2 ON t2.a>53 LEFT JOIN t3 ON NOT t2.a IS NOT NULL;
-- Test LOJ with subquery
--
-- Test various combinations
--
-- 1. LOJ outside subquery
--
/*+
Leading(((t5 t4) (t3 (t1 t2))))
*/
EXPLAIN (costs off)
SELECT * FROM (SELECT t1.a FROM t1, t2 ORDER BY 1 LIMIT 42) AS q LEFT JOIN t3 ON t3.a=q.a, t4, t5;
/*+
Leading((((t1 t2) t3) (t4 t5)))
*/
EXPLAIN (costs off)
SELECT * FROM (SELECT t1.a FROM t1, t2 ORDER BY 1 LIMIT 42) AS q LEFT JOIN t3 ON t3.a=q.a, t4, t5;
--
-- 2. LOJ inside subquery
--
/*+
Leading(((t5 t4) (t3 (t1 t2))))
*/
EXPLAIN (costs off)
SELECT * FROM (SELECT t1.a FROM t1 LEFT JOIN t2 ON t1.a=t2.a ORDER BY 1 LIMIT 42) AS q, t3, t4, t5;
/*+
Leading((((t2 t1) t3) (t4 t5)))
*/
EXPLAIN (costs off)
SELECT * FROM (SELECT t1.a FROM t1 LEFT JOIN t2 ON t1.a=t2.a ORDER BY 1 LIMIT 42) AS q, t3, t4, t5;
--
-- 2. LOJ inside/outside subquery
--
/*+
Leading(((t5 t4) (t3 (t1 t2))))
*/
EXPLAIN (costs off)
SELECT * FROM (SELECT t1.a FROM t1 LEFT JOIN t2 ON t1.a=t2.a ORDER BY 1 LIMIT 42) AS q LEFT JOIN t3 ON q.a=t3.a, t4, t5;
/*+
Leading((((t2 t1) t3) (t4 t5)))
*/
EXPLAIN (costs off)
SELECT * FROM (SELECT t1.a FROM t1 LEFT JOIN t2 ON t1.a=t2.a ORDER BY 1 LIMIT 42) AS q LEFT JOIN t3 ON q.a=t3.a, t4, t5;
RESET client_min_messages;
RESET pg_hint_plan.debug_print;