Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable all join operators for all joins for n rels if there is no join hint for n rels #208

Open
wants to merge 2 commits into
base: PG16
Choose a base branch
from

Conversation

HennyNile
Copy link

Hi, I created this pull request to solve problems introduced in #207 which I will introduce later. But this pull request is independent of #207 and it only modifies several lines of code.

For a query (from a test file) with hints like

/*+Leading( t3 t4 ) */ 
explain SELECT * FROM t1, t2, t3, t4 WHERE t1.id = t2.id AND t1.id = t3.id AND t1.id = t4.id;

The hint only includes the join hints for join (t3 t4) and the generated plan is

                                      QUERY PLAN                                       
---------------------------------------------------------------------------------------
 Nested Loop  (cost=20000000001.97..20000000010.32 rows=1 width=32)
   ->  Nested Loop  (cost=10000000001.68..10000000009.72 rows=1 width=24)
         ->  Merge Join  (cost=1.41..2.80 rows=10 width=16)
               Merge Cond: (t3.id = t4.id)
               ->  Index Scan using t3_pkey on t3  (cost=0.14..13.64 rows=100 width=8)
               ->  Sort  (cost=1.27..1.29 rows=10 width=8)
                     Sort Key: t4.id
                     ->  Seq Scan on t4  (cost=0.00..1.10 rows=10 width=8)
         ->  Index Scan using t2_pkey on t2  (cost=0.28..0.69 rows=1 width=8)
               Index Cond: (id = t3.id)
   ->  Index Scan using t1_pkey on t1  (cost=0.29..0.60 rows=1 width=8)
         Index Cond: (id = t2.id)
(12 rows)

In this plan, a disable_cost (1e10) has been added to the cost of nestloop(t2 t3 t4) and two have been added to nestloop(t1 t2 t3 t4). This is because pg_hint adds a disable_cost to the cost of all joins without a join hint, even if there is no join hint for all joins with the same number of relations. In this example, a disable_cost will be added to all joins with 3 relations and two will be added to all joins with 4 relations.

It may be more reasonable to omit to add a disable_cost to all joins involving n relations if no join hint is provided for such joins. What's more, we want to enlarge the disable_cost to 1e20 in #207. Such a large disable_cost will lead to the wrong comparison of the costs of two disabled paths. For example, if the actual cost of the disabled path A is 12.3 and the actual cost of the disabled path B is 20, with a disable_cost (1e20), they will have the same cost because float only has approximately 15-17 decimal digits of precision. Thus, a worse path will be selected in some cases. Therefore, we should omit to add a disable_cost to all joins involving n relations if no join hint is provided for such joins.

After applying this modification, I ran the test and found some queries generated different plans with the expected. The following is one example from test pg_hint_plan.sql.

Query
------
/*+Leading( t3 t4 )*/
EXPLAIN (COSTS false) SELECT * FROM t1, t2, t3, t4 WHERE t1.id = t2.id AND t1.id = t3.id AND t1.id = t4.id;
Actual Plan
-----------
                                      QUERY PLAN                                       
---------------------------------------------------------------------------------------
 Nested Loop  (cost=1.97..6.93 rows=1 width=32)
   ->  Merge Join  (cost=1.69..6.64 rows=1 width=24)
         Merge Cond: (t3.id = t1.id)
         ->  Merge Join  (cost=1.41..2.80 rows=10 width=16)
               Merge Cond: (t3.id = t4.id)
               ->  Index Scan using t3_pkey on t3  (cost=0.14..13.64 rows=100 width=8)
               ->  Sort  (cost=1.27..1.29 rows=10 width=8)
                     Sort Key: t4.id
                     ->  Seq Scan on t4  (cost=0.00..1.10 rows=10 width=8)
         ->  Index Scan using t1_pkey on t1  (cost=0.29..318.29 rows=10000 width=8)
   ->  Index Scan using t2_pkey on t2  (cost=0.28..0.30 rows=1 width=8)
         Index Cond: (id = t1.id)
(12 rows)
Expected Plan (generated with additional hints)
-----------------------------------------------
                                      QUERY PLAN                                       
---------------------------------------------------------------------------------------
 Nested Loop  (cost=1.97..10.32 rows=1 width=32)
   ->  Nested Loop  (cost=1.68..9.72 rows=1 width=24)
         ->  Merge Join  (cost=1.41..2.80 rows=10 width=16)
               Merge Cond: (t3.id = t4.id)
               ->  Index Scan using t3_pkey on t3  (cost=0.14..13.64 rows=100 width=8)
               ->  Sort  (cost=1.27..1.29 rows=10 width=8)
                     Sort Key: t4.id
                     ->  Seq Scan on t4  (cost=0.00..1.10 rows=10 width=8)
         ->  Index Scan using t2_pkey on t2  (cost=0.28..0.69 rows=1 width=8)
               Index Cond: (id = t3.id)
   ->  Index Scan using t1_pkey on t1  (cost=0.29..0.60 rows=1 width=8)
         Index Cond: (id = t2.id)
(12 rows)

We could see that the expected plan in the test file has a larger cost than the actual generated plan. I checked all differences and found all actual plans have less costs.So if we apply this modification, we need to update the expected plans for test sqls. I hope you apply this modification and check if you will generate different plans with the expected plans.

In summary, I want to demonstrate two things in this pull request:

  • It may be more reasonable to omit to add a disable_cost to all joins involving n relations if no join hint is provided for such joins.
  • With the above modifications, the expected results of test sqls may need to be updated.

Hope your reply!

@HennyNile
Copy link
Author

In this comment, for these test queries which generate unexpected plans with the above modifications, I present their actual plans and expected plans. It's obviously that all actual plans has less cost, thus we may need to update the expected test results.

pg_hint_plan.sql

Q1
--
/*+Leading( t3 t4 )*/
EXPLAIN SELECT * FROM t1, t2, t3, t4 WHERE t1.id = t2.id AND t1.id = t3.id AND t1.id = t4.id;

Actual Plan
-----------
                                      QUERY PLAN                                       
---------------------------------------------------------------------------------------
 Nested Loop  (cost=1.97..6.93 rows=1 width=32)
   ->  Merge Join  (cost=1.69..6.64 rows=1 width=24)
         Merge Cond: (t3.id = t1.id)
         ->  Merge Join  (cost=1.41..2.80 rows=10 width=16)
               Merge Cond: (t3.id = t4.id)
               ->  Index Scan using t3_pkey on t3  (cost=0.14..13.64 rows=100 width=8)
               ->  Sort  (cost=1.27..1.29 rows=10 width=8)
                     Sort Key: t4.id
                     ->  Seq Scan on t4  (cost=0.00..1.10 rows=10 width=8)
         ->  Index Scan using t1_pkey on t1  (cost=0.29..318.29 rows=10000 width=8)
   ->  Index Scan using t2_pkey on t2  (cost=0.28..0.30 rows=1 width=8)
         Index Cond: (id = t1.id)
(12 rows)

Expected Plans (generated with additional hints)
------------------------------------------------
                                      QUERY PLAN                                       
---------------------------------------------------------------------------------------
 Nested Loop  (cost=1.97..10.32 rows=1 width=32)
   ->  Nested Loop  (cost=1.68..9.72 rows=1 width=24)
         ->  Merge Join  (cost=1.41..2.80 rows=10 width=16)
               Merge Cond: (t3.id = t4.id)
               ->  Index Scan using t3_pkey on t3  (cost=0.14..13.64 rows=100 width=8)
               ->  Sort  (cost=1.27..1.29 rows=10 width=8)
                     Sort Key: t4.id
                     ->  Seq Scan on t4  (cost=0.00..1.10 rows=10 width=8)
         ->  Index Scan using t2_pkey on t2  (cost=0.28..0.69 rows=1 width=8)
               Index Cond: (id = t3.id)
   ->  Index Scan using t1_pkey on t1  (cost=0.29..0.60 rows=1 width=8)
         Index Cond: (id = t2.id)
(12 rows)
---------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------
Q2
--
/*+Leading((t1 t2))*/
EXPLAIN SELECT * FROM t1, t2, t3 WHERE t1.id = t2.id AND t2.val = t3.val AND t1.id < 10;

Actual Plan
-----------
                                     QUERY PLAN                                     
------------------------------------------------------------------------------------
 Hash Join  (cost=35.98..38.36 rows=1 width=24)
   Hash Cond: (t3.val = t2.val)
   ->  Seq Scan on t3  (cost=0.00..2.00 rows=100 width=8)
   ->  Hash  (cost=35.97..35.97 rows=1 width=16)
         ->  Hash Join  (cost=27.79..35.97 rows=1 width=16)
               Hash Cond: (t1.id = t2.id)
               ->  Index Scan using t1_pkey on t1  (cost=0.29..8.44 rows=9 width=8)
                     Index Cond: (id < 10)
               ->  Hash  (cost=15.00..15.00 rows=1000 width=8)
                     ->  Seq Scan on t2  (cost=0.00..15.00 rows=1000 width=8)
(10 rows)

Expected Plans (generated with additional hints)
------------------------------------------------
                                     QUERY PLAN                                  
------------------------------------------------------------------------------
 Nested Loop  (cost=27.79..39.22 rows=1 width=24)
   Join Filter: (t2.val = t3.val)
   ->  Hash Join  (cost=27.79..35.97 rows=1 width=16)
         Hash Cond: (t1.id = t2.id)
         ->  Index Scan using t1_pkey on t1  (cost=0.29..8.44 rows=9 width=8)
               Index Cond: (id < 10)
         ->  Hash  (cost=15.00..15.00 rows=1000 width=8)
               ->  Seq Scan on t2  (cost=0.00..15.00 rows=1000 width=8)
   ->  Seq Scan on t3  (cost=0.00..2.00 rows=100 width=8)
(9 rows)
---------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------
Q3
--
/*+Leading(((t1 t2) t3)) MergeJoin(t3 t4)*/
EXPLAIN SELECT * FROM t1, t2, t3, t4 WHERE t1.id = t2.id AND t3.id = t4.id AND t1.val = t3.val AND t1.id < 10;

Actual Plan
-----------
                                     QUERY PLAN                                     
------------------------------------------------------------------------------------
 Nested Loop  (cost=27.92..39.51 rows=1 width=32)
   ->  Nested Loop  (cost=27.79..39.22 rows=1 width=24)
         Join Filter: (t1.val = t3.val)
         ->  Hash Join  (cost=27.79..35.97 rows=1 width=16)
               Hash Cond: (t1.id = t2.id)
               ->  Index Scan using t1_pkey on t1  (cost=0.29..8.44 rows=9 width=8)
                     Index Cond: (id < 10)
               ->  Hash  (cost=15.00..15.00 rows=1000 width=8)
                     ->  Seq Scan on t2  (cost=0.00..15.00 rows=1000 width=8)
         ->  Seq Scan on t3  (cost=0.00..2.00 rows=100 width=8)
   ->  Index Scan using t4_pkey on t4  (cost=0.14..0.27 rows=1 width=8)
         Index Cond: (id = t3.id)
(12 rows)

Expected Plans (generated with additional hints)
------------------------------------------------
                                     QUERY PLAN                                     
------------------------------------------------------------------------------------
 Nested Loop  (cost=27.79..40.44 rows=1 width=32)
   Join Filter: (t3.id = t4.id)
   ->  Nested Loop  (cost=27.79..39.22 rows=1 width=24)
         Join Filter: (t1.val = t3.val)
         ->  Hash Join  (cost=27.79..35.97 rows=1 width=16)
               Hash Cond: (t1.id = t2.id)
               ->  Index Scan using t1_pkey on t1  (cost=0.29..8.44 rows=9 width=8)
                     Index Cond: (id < 10)
               ->  Hash  (cost=15.00..15.00 rows=1000 width=8)
                     ->  Seq Scan on t2  (cost=0.00..15.00 rows=1000 width=8)
         ->  Seq Scan on t3  (cost=0.00..2.00 rows=100 width=8)
   ->  Seq Scan on t4  (cost=0.00..1.10 rows=10 width=8)
(12 rows)
---------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------
Q4
--
/*+ SeqScan(t1) MergeJoin(t1 t2) Leading(t1 t2) Rows(t1 t2 +10) Parallel(t1 8 hard) Set(random_page_cost 2.0)*/
EXPLAIN SELECT * FROM t1 JOIN t2 ON (t1.id = t2.id) JOIN t3 ON (t3.id = t2.id);

Actual Plan
-----------
                                      QUERY PLAN                                      
--------------------------------------------------------------------------------------
 Merge Join  (cost=669.99..671.09 rows=10 width=24)
   Merge Cond: (t1.id = t3.id)
   ->  Merge Join  (cost=664.67..713.16 rows=1010 width=16)
         Merge Cond: (t2.id = t1.id)
         ->  Index Scan using t2_pkey on t2  (cost=0.28..31.27 rows=1000 width=8)
         ->  Sort  (cost=664.39..689.39 rows=10000 width=8)
               Sort Key: t1.id
               ->  Gather  (cost=0.00..0.00 rows=10000 width=8)
                     Workers Planned: 8
                     ->  Parallel Seq Scan on t1  (cost=0.00..0.00 rows=2500 width=8)
   ->  Sort  (cost=5.32..5.57 rows=100 width=8)
         Sort Key: t3.id
         ->  Seq Scan on t3  (cost=0.00..2.00 rows=100 width=8)
(13 rows)

Expected Plans (generated with additional hints)
------------------------------------------------
                                      QUERY PLAN                                      
--------------------------------------------------------------------------------------
 Nested Loop  (cost=664.81..875.37 rows=10 width=24)
   ->  Merge Join  (cost=664.67..713.16 rows=1010 width=16)
         Merge Cond: (t2.id = t1.id)
         ->  Index Scan using t2_pkey on t2  (cost=0.28..31.27 rows=1000 width=8)
         ->  Sort  (cost=664.39..689.39 rows=10000 width=8)
               Sort Key: t1.id
               ->  Gather  (cost=0.00..0.00 rows=10000 width=8)
                     Workers Planned: 8
                     ->  Parallel Seq Scan on t1  (cost=0.00..0.00 rows=2500 width=8)
   ->  Index Scan using t3_pkey on t3  (cost=0.14..0.16 rows=1 width=8)
         Index Cond: (id = t1.id)
(11 rows)

ut-L.sql

Q1
--
/*+Leading((t2 t3))*/
EXPLAIN SELECT * FROM s1.t1, s1.t2, s1.t3, s1.t4 WHERE t1.c1 = t2.c1 AND t1.c1 = t3.c1 AND t1.c1 = t4.c1;

Actual Plan
-----------
                                      QUERY PLAN                                      
-------------------------------------------------------------------------------------
 Nested Loop  (cost=41.44..68.83 rows=100 width=117)
   ->  Merge Join  (cost=41.28..47.43 rows=100 width=73)
         Merge Cond: (t1.c1 = t2.c1)
         ->  Index Scan using t1_i1 on t1  (cost=0.28..44.27 rows=1000 width=15)
         ->  Sort  (cost=41.01..41.26 rows=100 width=58)
               Sort Key: t2.c1
               ->  Hash Join  (cost=35.42..37.69 rows=100 width=58)
                     Hash Cond: (t2.c1 = t3.c1)
                     ->  Seq Scan on t2  (cost=0.00..2.00 rows=100 width=14)
                     ->  Hash  (cost=21.30..21.30 rows=1130 width=44)
                           ->  Seq Scan on t3  (cost=0.00..21.30 rows=1130 width=44)
   ->  Index Scan using t4_i1 on t4  (cost=0.15..0.21 rows=1 width=44)
         Index Cond: (c1 = t1.c1)
(13 rows)

Expected Plans (generated with additional hints)
------------------------------------------------
                                      QUERY PLAN                                      
--------------------------------------------------------------------------------------
 Nested Loop  (cost=0.72..130.44 rows=100 width=117)
   ->  Nested Loop  (cost=0.57..109.04 rows=100 width=73)
         Join Filter: (t1.c1 = t2.c1)
         ->  Nested Loop  (cost=0.30..74.64 rows=100 width=58)
               ->  Index Scan using t2_i1 on t2  (cost=0.14..13.64 rows=100 width=14)
               ->  Index Scan using t3_i1 on t3  (cost=0.15..0.61 rows=1 width=44)
                     Index Cond: (c1 = t2.c1)
         ->  Index Scan using t1_i1 on t1  (cost=0.28..0.33 rows=1 width=15)
               Index Cond: (c1 = t3.c1)
   ->  Index Scan using t4_i1 on t4  (cost=0.15..0.21 rows=1 width=44)
         Index Cond: (c1 = t1.c1)
(11 rows)

ut-R.sql

Q1
--
/*+
Leading(c1 bmt2 bmt1)
Leading(b1t2 b1t1)
Leading(b2t2 b2t1)
Leading(b3t2 b3t1)
MergeJoin(c1 bmt2)
HashJoin(c1 bmt1 bmt2)
MergeJoin(b1t1 b1t2)
MergeJoin(b2t1 b2t2)
MergeJoin(b3t1 b3t2)
*/
EXPLAIN
WITH c1 (c1) AS (
SELECT b1t1.c1 FROM s1.t1 b1t1, s1.t2 b1t2 WHERE b1t1.c1 = b1t2.c1
)
SELECT bmt1.c1, (
SELECT b2t1.c1 FROM s1.t1 b2t1, s1.t2 b2t2 WHERE b2t1.c1 = b2t2.c1
)
                    FROM s1.t1 bmt1, s1.t2 bmt2, c1 WHERE bmt1.c1 = bmt2.c1
AND bmt1.c1 = c1.c1
AND bmt1.c1 <> (
SELECT b3t1.c1 FROM s1.t1 b3t1, s1.t2 b3t2 WHERE b3t1.c1 = b3t2.c1
);

Actual Plan
-----------
                                      QUERY PLAN                                           
------------------------------------------------------------------------------------------------
 Merge Join  (cost=34.69..39.29 rows=10 width=8)
   Merge Cond: (bmt1.c1 = bmt2.c1)
   InitPlan 1 (returns $0)
     ->  Merge Join  (cost=5.60..11.75 rows=100 width=4)
           Merge Cond: (b2t1.c1 = b2t2.c1)
           ->  Index Only Scan using t1_i1 on t1 b2t1  (cost=0.28..44.27 rows=1000 width=4)
           ->  Sort  (cost=5.32..5.57 rows=100 width=4)
                 Sort Key: b2t2.c1
                 ->  Seq Scan on t2 b2t2  (cost=0.00..2.00 rows=100 width=4)
   InitPlan 2 (returns $1)
     ->  Merge Join  (cost=5.60..11.75 rows=100 width=4)
           Merge Cond: (b3t1.c1 = b3t2.c1)
           ->  Index Only Scan using t1_i1 on t1 b3t1  (cost=0.28..44.27 rows=1000 width=4)
           ->  Sort  (cost=5.32..5.57 rows=100 width=4)
                 Sort Key: b3t2.c1
                 ->  Seq Scan on t2 b3t2  (cost=0.00..2.00 rows=100 width=4)
   ->  Nested Loop  (cost=5.87..45.65 rows=100 width=12)
         ->  Merge Join  (cost=5.60..11.75 rows=100 width=8)
               Merge Cond: (b1t1.c1 = b1t2.c1)
               ->  Index Only Scan using t1_i1 on t1 b1t1  (cost=0.28..44.27 rows=1000 width=4)
               ->  Sort  (cost=5.32..5.57 rows=100 width=4)
                     Sort Key: b1t2.c1
                     ->  Seq Scan on t2 b1t2  (cost=0.00..2.00 rows=100 width=4)
         ->  Index Only Scan using t1_i1 on t1 bmt1  (cost=0.28..0.34 rows=1 width=4)
               Index Cond: (c1 = b1t1.c1)
               Filter: (c1 <> $1)
   ->  Sort  (cost=5.32..5.57 rows=100 width=4)
         Sort Key: bmt2.c1
         ->  Seq Scan on t2 bmt2  (cost=0.00..2.00 rows=100 width=4)
(29 rows)

Expected Plans (generated with additional hints)
------------------------------------------------
                                      QUERY PLAN                                           
------------------------------------------------------------------------------------------------
 Nested Loop  (cost=29.51..87.59 rows=10 width=8)
   Join Filter: (bmt1.c1 = bmt2.c1)
   InitPlan 1 (returns $0)
     ->  Merge Join  (cost=5.60..11.75 rows=100 width=4)
           Merge Cond: (b2t1.c1 = b2t2.c1)
           ->  Index Only Scan using t1_i1 on t1 b2t1  (cost=0.28..44.27 rows=1000 width=4)
           ->  Sort  (cost=5.32..5.57 rows=100 width=4)
                 Sort Key: b2t2.c1
                 ->  Seq Scan on t2 b2t2  (cost=0.00..2.00 rows=100 width=4)
   InitPlan 2 (returns $1)
     ->  Merge Join  (cost=5.60..11.75 rows=100 width=4)
           Merge Cond: (b3t1.c1 = b3t2.c1)
           ->  Index Only Scan using t1_i1 on t1 b3t1  (cost=0.28..44.27 rows=1000 width=4)
           ->  Sort  (cost=5.32..5.57 rows=100 width=4)
                 Sort Key: b3t2.c1
                 ->  Seq Scan on t2 b3t2  (cost=0.00..2.00 rows=100 width=4)
   ->  Nested Loop  (cost=5.87..45.65 rows=100 width=12)
         ->  Merge Join  (cost=5.60..11.75 rows=100 width=8)
               Merge Cond: (b1t1.c1 = b1t2.c1)
               ->  Index Only Scan using t1_i1 on t1 b1t1  (cost=0.28..44.27 rows=1000 width=4)
               ->  Sort  (cost=5.32..5.57 rows=100 width=4)
                     Sort Key: b1t2.c1
                     ->  Seq Scan on t2 b1t2  (cost=0.00..2.00 rows=100 width=4)
         ->  Index Only Scan using t1_i1 on t1 bmt1  (cost=0.28..0.34 rows=1 width=4)
               Index Cond: (c1 = b1t1.c1)
               Filter: (c1 <> $1)
   ->  Index Only Scan using t2_i1 on t2 bmt2  (cost=0.14..0.17 rows=1 width=4)
         Index Cond: (c1 = b1t1.c1)
(28 rows)
---------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------
Q2
--
/*+
Leading(c1 bmt2 bmt1)
Leading(b1t2 b1t1)
Leading(b2t2 b2t1)
Leading(b3t2 b3t1)
MergeJoin(c1 bmt2)
HashJoin(c1 bmt1 bmt2)
MergeJoin(b1t1 b1t2)
MergeJoin(b2t1 b2t2)
MergeJoin(b3t1 b3t2)
Rows(c1 bmt2 #1)
Rows(c1 bmt1 bmt2 #1)
Rows(b1t1 b1t2 #1)
Rows(b2t1 b2t2 #1)
Rows(b3t1 b3t2 #1)
*/
EXPLAIN
WITH c1 (c1) AS (
SELECT b1t1.c1 FROM s1.t1 b1t1, s1.t2 b1t2 WHERE b1t1.c1 = b1t2.c1
)
SELECT bmt1.c1, (
SELECT b2t1.c1 FROM s1.t1 b2t1, s1.t2 b2t2 WHERE b2t1.c1 = b2t2.c1
)
                    FROM s1.t1 bmt1, s1.t2 bmt2, c1 WHERE bmt1.c1 = bmt2.c1
AND bmt1.c1 = c1.c1
AND bmt1.c1 <> (
SELECT b3t1.c1 FROM s1.t1 b3t1, s1.t2 b3t2 WHERE b3t1.c1 = b3t2.c1
)
;

Actual Plan
-----------
                                      QUERY PLAN                                           
------------------------------------------------------------------------------------------------
 Merge Join  (cost=34.69..35.93 rows=10 width=8)
   Merge Cond: (bmt1.c1 = bmt2.c1)
   InitPlan 1 (returns $0)
     ->  Merge Join  (cost=5.60..11.75 rows=1 width=4)
           Merge Cond: (b2t1.c1 = b2t2.c1)
           ->  Index Only Scan using t1_i1 on t1 b2t1  (cost=0.28..44.27 rows=1000 width=4)
           ->  Sort  (cost=5.32..5.57 rows=100 width=4)
                 Sort Key: b2t2.c1
                 ->  Seq Scan on t2 b2t2  (cost=0.00..2.00 rows=100 width=4)
   InitPlan 2 (returns $1)
     ->  Merge Join  (cost=5.60..11.75 rows=1 width=4)
           Merge Cond: (b3t1.c1 = b3t2.c1)
           ->  Index Only Scan using t1_i1 on t1 b3t1  (cost=0.28..44.27 rows=1000 width=4)
           ->  Sort  (cost=5.32..5.57 rows=100 width=4)
                 Sort Key: b3t2.c1
                 ->  Seq Scan on t2 b3t2  (cost=0.00..2.00 rows=100 width=4)
   ->  Nested Loop  (cost=5.87..12.09 rows=100 width=12)
         ->  Merge Join  (cost=5.60..11.75 rows=1 width=8)
               Merge Cond: (b1t1.c1 = b1t2.c1)
               ->  Index Only Scan using t1_i1 on t1 b1t1  (cost=0.28..44.27 rows=1000 width=4)
               ->  Sort  (cost=5.32..5.57 rows=100 width=4)
                     Sort Key: b1t2.c1
                     ->  Seq Scan on t2 b1t2  (cost=0.00..2.00 rows=100 width=4)
         ->  Index Only Scan using t1_i1 on t1 bmt1  (cost=0.28..0.34 rows=1 width=4)
               Index Cond: (c1 = b1t1.c1)
               Filter: (c1 <> $1)
   ->  Sort  (cost=5.32..5.57 rows=100 width=4)
         Sort Key: bmt2.c1
         ->  Seq Scan on t2 bmt2  (cost=0.00..2.00 rows=100 width=4)
(29 rows)

Expected Plans (generated with additional hints)
------------------------------------------------
                                      QUERY PLAN                                           
------------------------------------------------------------------------------------------------
 Nested Loop  (cost=29.51..54.03 rows=10 width=8)
   Join Filter: (bmt1.c1 = bmt2.c1)
   InitPlan 1 (returns $0)
     ->  Merge Join  (cost=5.60..11.75 rows=1 width=4)
           Merge Cond: (b2t1.c1 = b2t2.c1)
           ->  Index Only Scan using t1_i1 on t1 b2t1  (cost=0.28..44.27 rows=1000 width=4)
           ->  Sort  (cost=5.32..5.57 rows=100 width=4)
                 Sort Key: b2t2.c1
                 ->  Seq Scan on t2 b2t2  (cost=0.00..2.00 rows=100 width=4)
   InitPlan 2 (returns $1)
     ->  Merge Join  (cost=5.60..11.75 rows=1 width=4)
           Merge Cond: (b3t1.c1 = b3t2.c1)
           ->  Index Only Scan using t1_i1 on t1 b3t1  (cost=0.28..44.27 rows=1000 width=4)
           ->  Sort  (cost=5.32..5.57 rows=100 width=4)
                 Sort Key: b3t2.c1
                 ->  Seq Scan on t2 b3t2  (cost=0.00..2.00 rows=100 width=4)
   ->  Nested Loop  (cost=5.87..12.09 rows=100 width=12)
         ->  Merge Join  (cost=5.60..11.75 rows=1 width=8)
               Merge Cond: (b1t1.c1 = b1t2.c1)
               ->  Index Only Scan using t1_i1 on t1 b1t1  (cost=0.28..44.27 rows=1000 width=4)
               ->  Sort  (cost=5.32..5.57 rows=100 width=4)
                     Sort Key: b1t2.c1
                     ->  Seq Scan on t2 b1t2  (cost=0.00..2.00 rows=100 width=4)
         ->  Index Only Scan using t1_i1 on t1 bmt1  (cost=0.28..0.34 rows=1 width=4)
               Index Cond: (c1 = b1t1.c1)
               Filter: (c1 <> $1)
   ->  Index Only Scan using t2_i1 on t2 bmt2  (cost=0.14..0.17 rows=1 width=4)
         Index Cond: (c1 = b1t1.c1)
(28 rows)
---------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------
Q3
--
/*+
Leading(c1 bmt4 bmt3 bmt2 bmt1)
Leading(b1t4 b1t3 b1t2 b1t1) 
Leading(b2t4 b2t3 b2t2 b2t1)
Leading(b3t4 b3t3 b3t2 b3t1)
MergeJoin(c1 bmt4)
HashJoin(c1 bmt4 bmt3)
NestLoop(c1 bmt4 bmt3 bmt2)
MergeJoin(c1 bmt4 bmt3 bmt2 bmt1)
HashJoin(b1t4 b1t3)
NestLoop(b1t4 b1t3 b1t2)
MergeJoin(b1t4 b1t3 b1t2 b1t1)
HashJoin(b2t4 b2t3)
NestLoop(b2t4 b2t3 b2t2)
MergeJoin(b2t4 b2t3 b2t2 b2t1)
HashJoin(b3t4 b3t3)
NestLoop(b3t4 b3t3 b3t2)
MergeJoin(b3t4 b3t3 b3t2 b3t1)
*/
EXPLAIN
WITH c1 (c1) AS (
SELECT b1t1.c1 FROM s1.t1 b1t1, s1.t2 b1t2, s1.t3 b1t3, s1.t4 b1t4 WHERE b1t1.c1 = b1t2.c1 AND b1t1.c1 = b1t3.c1 AND b1t1.c1 = b1t4.c1
)
SELECT bmt1.c1, (
SELECT b2t1.c1 FROM s1.t1 b2t1, s1.t2 b2t2, s1.t3 b2t3, s1.t4 b2t4 WHERE b2t1.c1 = b2t2.c1 AND b2t1.c1 = b2t3.c1 AND b2t1.c1 = b2t4.c1
)
                    FROM s1.t1 bmt1, s1.t2 bmt2, s1.t3 bmt3, s1.t4 bmt4, c1 WHERE bmt1.c1 = bmt2.c1 AND bmt1.c1 = bmt3.c1 AND bmt1.c1 = bmt4.c1 AND bmt1.c1 = c1.c1
AND bmt1.c1 <> (
SELECT b3t1.c1 FROM s1.t1 b3t1, s1.t2 b3t2, s1.t3 b3t3, s1.t4 b3t4 WHERE b3t1.c1 = b3t2.c1 AND b3t1.c1 = b3t3.c1 AND b3t1.c1 = b3t4.c1
);

Actual Plan
-----------
                                      QUERY PLAN                                                     
--------------------------------------------------------------------------------------------------------------------
 Merge Join  (cost=786.42..794.52 rows=10 width=8)
   Merge Cond: (bmt1.c1 = bmt2.c1)
   InitPlan 1 (returns $1)
     ->  Merge Join  (cost=256.07..262.22 rows=100 width=4)
           Merge Cond: (b2t1.c1 = b2t2.c1)
           ->  Index Only Scan using t1_i1 on t1 b2t1  (cost=0.28..44.27 rows=1000 width=4)
           ->  Sort  (cost=255.80..256.05 rows=100 width=12)
                 Sort Key: b2t2.c1
                 ->  Nested Loop  (cost=35.57..252.48 rows=100 width=12)
                       ->  Hash Join  (cost=35.42..59.70 rows=1130 width=8)
                             Hash Cond: (b2t3.c1 = b2t4.c1)
                             ->  Seq Scan on t3 b2t3  (cost=0.00..21.30 rows=1130 width=4)
                             ->  Hash  (cost=21.30..21.30 rows=1130 width=4)
                                   ->  Seq Scan on t4 b2t4  (cost=0.00..21.30 rows=1130 width=4)
                       ->  Index Only Scan using t2_i1 on t2 b2t2  (cost=0.14..0.17 rows=1 width=4)
                             Index Cond: (c1 = b2t3.c1)
   InitPlan 2 (returns $3)
     ->  Merge Join  (cost=256.07..262.22 rows=100 width=4)
           Merge Cond: (b3t1.c1 = b3t2.c1)
           ->  Index Only Scan using t1_i1 on t1 b3t1  (cost=0.28..44.27 rows=1000 width=4)
           ->  Sort  (cost=255.80..256.05 rows=100 width=12)
                 Sort Key: b3t2.c1
                 ->  Nested Loop  (cost=35.57..252.48 rows=100 width=12)
                       ->  Hash Join  (cost=35.42..59.70 rows=1130 width=8)
                             Hash Cond: (b3t3.c1 = b3t4.c1)
                             ->  Seq Scan on t3 b3t3  (cost=0.00..21.30 rows=1130 width=4)
                             ->  Hash  (cost=21.30..21.30 rows=1130 width=4)
                                   ->  Seq Scan on t4 b3t4  (cost=0.00..21.30 rows=1130 width=4)
                       ->  Index Only Scan using t2_i1 on t2 b3t2  (cost=0.14..0.17 rows=1 width=4)
                             Index Cond: (c1 = b3t3.c1)
   ->  Nested Loop  (cost=256.65..331.40 rows=100 width=28)
         ->  Nested Loop  (cost=256.38..302.01 rows=88 width=24)
               ->  Nested Loop  (cost=256.22..283.62 rows=88 width=20)
                     ->  Merge Join  (cost=256.07..262.22 rows=100 width=16)
                           Merge Cond: (b1t1.c1 = b1t2.c1)
                           ->  Index Only Scan using t1_i1 on t1 b1t1  (cost=0.28..44.27 rows=1000 width=4)
                           ->  Sort  (cost=255.80..256.05 rows=100 width=12)
                                 Sort Key: b1t2.c1
                                 ->  Nested Loop  (cost=35.57..252.48 rows=100 width=12)
                                       ->  Hash Join  (cost=35.42..59.70 rows=1130 width=8)
                                             Hash Cond: (b1t3.c1 = b1t4.c1)
                                             ->  Seq Scan on t3 b1t3  (cost=0.00..21.30 rows=1130 width=4)
                                             ->  Hash  (cost=21.30..21.30 rows=1130 width=4)
                                                   ->  Seq Scan on t4 b1t4  (cost=0.00..21.30 rows=1130 width=4)
                                       ->  Index Only Scan using t2_i1 on t2 b1t2  (cost=0.14..0.17 rows=1 width=4)
                                             Index Cond: (c1 = b1t3.c1)
                     ->  Index Only Scan using t3_i1 on t3 bmt3  (cost=0.15..0.21 rows=1 width=4)
                           Index Cond: (c1 = b1t1.c1)
               ->  Index Only Scan using t4_i1 on t4 bmt4  (cost=0.15..0.21 rows=1 width=4)
                     Index Cond: (c1 = bmt3.c1)
         ->  Index Only Scan using t1_i1 on t1 bmt1  (cost=0.28..0.33 rows=1 width=4)
               Index Cond: (c1 = bmt3.c1)
               Filter: (c1 <> $3)
   ->  Sort  (cost=5.32..5.57 rows=100 width=4)
         Sort Key: bmt2.c1
         ->  Seq Scan on t2 bmt2  (cost=0.00..2.00 rows=100 width=4)
(56 rows)


Expected Plans (generated with additional hints)
------------------------------------------------
                                      QUERY PLAN                                                     
--------------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=781.24..844.05 rows=10 width=8)
   Join Filter: (bmt1.c1 = bmt4.c1)
   InitPlan 1 (returns $1)
     ->  Merge Join  (cost=256.07..262.22 rows=100 width=4)
           Merge Cond: (b2t1.c1 = b2t2.c1)
           ->  Index Only Scan using t1_i1 on t1 b2t1  (cost=0.28..44.27 rows=1000 width=4)
           ->  Sort  (cost=255.80..256.05 rows=100 width=12)
                 Sort Key: b2t2.c1
                 ->  Nested Loop  (cost=35.57..252.48 rows=100 width=12)
                       ->  Hash Join  (cost=35.42..59.70 rows=1130 width=8)
                             Hash Cond: (b2t3.c1 = b2t4.c1)
                             ->  Seq Scan on t3 b2t3  (cost=0.00..21.30 rows=1130 width=4)
                             ->  Hash  (cost=21.30..21.30 rows=1130 width=4)
                                   ->  Seq Scan on t4 b2t4  (cost=0.00..21.30 rows=1130 width=4)
                       ->  Index Only Scan using t2_i1 on t2 b2t2  (cost=0.14..0.17 rows=1 width=4)
                             Index Cond: (c1 = b2t3.c1)
   InitPlan 2 (returns $3)
     ->  Merge Join  (cost=256.07..262.22 rows=100 width=4)
           Merge Cond: (b3t1.c1 = b3t2.c1)
           ->  Index Only Scan using t1_i1 on t1 b3t1  (cost=0.28..44.27 rows=1000 width=4)
           ->  Sort  (cost=255.80..256.05 rows=100 width=12)
                 Sort Key: b3t2.c1
                 ->  Nested Loop  (cost=35.57..252.48 rows=100 width=12)
                       ->  Hash Join  (cost=35.42..59.70 rows=1130 width=8)
                             Hash Cond: (b3t3.c1 = b3t4.c1)
                             ->  Seq Scan on t3 b3t3  (cost=0.00..21.30 rows=1130 width=4)
                             ->  Hash  (cost=21.30..21.30 rows=1130 width=4)
                                   ->  Seq Scan on t4 b3t4  (cost=0.00..21.30 rows=1130 width=4)
                       ->  Index Only Scan using t2_i1 on t2 b3t2  (cost=0.14..0.17 rows=1 width=4)
                             Index Cond: (c1 = b3t3.c1)
   ->  Nested Loop  (cost=256.64..317.39 rows=10 width=28)
         Join Filter: (bmt1.c1 = bmt3.c1)
         ->  Nested Loop  (cost=256.49..315.18 rows=10 width=24)
               Join Filter: (bmt1.c1 = bmt2.c1)
               ->  Nested Loop  (cost=256.35..296.87 rows=100 width=20)
                     Join Filter: (bmt1.c1 = b1t1.c1)
                     ->  Merge Join  (cost=256.07..262.22 rows=100 width=16)
                           Merge Cond: (b1t1.c1 = b1t2.c1)
                           ->  Index Only Scan using t1_i1 on t1 b1t1  (cost=0.28..44.27 rows=1000 width=4)
                           ->  Sort  (cost=255.80..256.05 rows=100 width=12)
                                 Sort Key: b1t2.c1
                                 ->  Nested Loop  (cost=35.57..252.48 rows=100 width=12)
                                       ->  Hash Join  (cost=35.42..59.70 rows=1130 width=8)
                                             Hash Cond: (b1t3.c1 = b1t4.c1)
                                             ->  Seq Scan on t3 b1t3  (cost=0.00..21.30 rows=1130 width=4)
                                             ->  Hash  (cost=21.30..21.30 rows=1130 width=4)
                                                   ->  Seq Scan on t4 b1t4  (cost=0.00..21.30 rows=1130 width=4)
                                       ->  Index Only Scan using t2_i1 on t2 b1t2  (cost=0.14..0.17 rows=1 width=4)
                                             Index Cond: (c1 = b1t3.c1)
                     ->  Index Only Scan using t1_i1 on t1 bmt1  (cost=0.28..0.33 rows=1 width=4)
                           Index Cond: (c1 = b1t3.c1)
                           Filter: (c1 <> $3)
               ->  Index Only Scan using t2_i1 on t2 bmt2  (cost=0.14..0.17 rows=1 width=4)
                     Index Cond: (c1 = b1t3.c1)
         ->  Index Only Scan using t3_i1 on t3 bmt3  (cost=0.15..0.21 rows=1 width=4)
               Index Cond: (c1 = b1t3.c1)
   ->  Index Only Scan using t4_i1 on t4 bmt4  (cost=0.15..0.21 rows=1 width=4)
         Index Cond: (c1 = bmt3.c1)
(58 rows)
---------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------
Q4
--
/*+
Leading(c1 bmt4 bmt3 bmt2 bmt1)
Leading(b1t4 b1t3 b1t2 b1t1) 
Leading(b2t4 b2t3 b2t2 b2t1)
Leading(b3t4 b3t3 b3t2 b3t1)
MergeJoin(c1 bmt4)
HashJoin(c1 bmt4 bmt3)
NestLoop(c1 bmt4 bmt3 bmt2)
MergeJoin(c1 bmt4 bmt3 bmt2 bmt1)
HashJoin(b1t4 b1t3)
NestLoop(b1t4 b1t3 b1t2)
MergeJoin(b1t4 b1t3 b1t2 b1t1)
HashJoin(b2t4 b2t3)
NestLoop(b2t4 b2t3 b2t2)
MergeJoin(b2t4 b2t3 b2t2 b2t1)
HashJoin(b3t4 b3t3)
NestLoop(b3t4 b3t3 b3t2)
MergeJoin(b3t4 b3t3 b3t2 b3t1)
Rows(c1 bmt4 #1)
Rows(c1 bmt4 bmt3 #1)
Rows(c1 bmt4 bmt3 bmt2 #1)
Rows(c1 bmt4 bmt3 bmt2 bmt1 #1)
Rows(b1t4 b1t3 #1)
Rows(b1t4 b1t3 b1t2 #1)
Rows(b1t4 b1t3 b1t2 b1t1 #1)
Rows(b2t4 b2t3 #1)
Rows(b2t4 b2t3 b2t2 #1)
Rows(b2t4 b2t3 b2t2 b2t1 #1)
Rows(b3t4 b3t3 #1)
Rows(b3t4 b3t3 b3t2 #1)
Rows(b3t4 b3t3 b3t2 b3t1 #1)
*/
EXPLAIN
WITH c1 (c1) AS (
SELECT b1t1.c1 FROM s1.t1 b1t1, s1.t2 b1t2, s1.t3 b1t3, s1.t4 b1t4 WHERE b1t1.c1 = b1t2.c1 AND b1t1.c1 = b1t3.c1 AND b1t1.c1 = b1t4.c1
)
SELECT bmt1.c1, (
SELECT b2t1.c1 FROM s1.t1 b2t1, s1.t2 b2t2, s1.t3 b2t3, s1.t4 b2t4 WHERE b2t1.c1 = b2t2.c1 AND b2t1.c1 = b2t3.c1 AND b2t1.c1 = b2t4.c1
)
                    FROM s1.t1 bmt1, s1.t2 bmt2, s1.t3 bmt3, s1.t4 bmt4, c1 WHERE bmt1.c1 = bmt2.c1 AND bmt1.c1 = bmt3.c1 AND bmt1.c1 = bmt4.c1 AND bmt1.c1 = c1.c1
AND bmt1.c1 <> (
SELECT b3t1.c1 FROM s1.t1 b3t1, s1.t2 b3t2, s1.t3 b3t3, s1.t4 b3t4 WHERE b3t1.c1 = b3t2.c1 AND b3t1.c1 = b3t3.c1 AND b3t1.c1 = b3t4.c1
);

Actual Plan
-----------
                                      QUERY PLAN                                                     
--------------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=195.71..200.79 rows=10 width=8)
   InitPlan 1 (returns $1)
     ->  Merge Join  (cost=60.16..64.83 rows=1 width=4)
           Merge Cond: (b2t1.c1 = b2t2.c1)
           ->  Index Only Scan using t1_i1 on t1 b2t1  (cost=0.28..44.27 rows=1000 width=4)
           ->  Sort  (cost=59.88..59.89 rows=1 width=12)
                 Sort Key: b2t2.c1
                 ->  Nested Loop  (cost=35.57..59.87 rows=1 width=12)
                       ->  Hash Join  (cost=35.42..59.70 rows=1 width=8)
                             Hash Cond: (b2t3.c1 = b2t4.c1)
                             ->  Seq Scan on t3 b2t3  (cost=0.00..21.30 rows=1130 width=4)
                             ->  Hash  (cost=21.30..21.30 rows=1130 width=4)
                                   ->  Seq Scan on t4 b2t4  (cost=0.00..21.30 rows=1130 width=4)
                       ->  Index Only Scan using t2_i1 on t2 b2t2  (cost=0.14..0.17 rows=1 width=4)
                             Index Cond: (c1 = b2t3.c1)
   InitPlan 2 (returns $3)
     ->  Merge Join  (cost=60.16..64.83 rows=1 width=4)
           Merge Cond: (b3t1.c1 = b3t2.c1)
           ->  Index Only Scan using t1_i1 on t1 b3t1  (cost=0.28..44.27 rows=1000 width=4)
           ->  Sort  (cost=59.88..59.89 rows=1 width=12)
                 Sort Key: b3t2.c1
                 ->  Nested Loop  (cost=35.57..59.87 rows=1 width=12)
                       ->  Hash Join  (cost=35.42..59.70 rows=1 width=8)
                             Hash Cond: (b3t3.c1 = b3t4.c1)
                             ->  Seq Scan on t3 b3t3  (cost=0.00..21.30 rows=1130 width=4)
                             ->  Hash  (cost=21.30..21.30 rows=1130 width=4)
                                   ->  Seq Scan on t4 b3t4  (cost=0.00..21.30 rows=1130 width=4)
                       ->  Index Only Scan using t2_i1 on t2 b3t2  (cost=0.14..0.17 rows=1 width=4)
                             Index Cond: (c1 = b3t3.c1)
   ->  Nested Loop  (cost=65.91..68.99 rows=10 width=28)
         ->  Merge Join  (cost=65.76..66.85 rows=10 width=24)
               Merge Cond: (bmt1.c1 = bmt2.c1)
               ->  Nested Loop  (cost=60.43..65.17 rows=100 width=20)
                     ->  Merge Join  (cost=60.16..64.83 rows=1 width=16)
                           Merge Cond: (b1t1.c1 = b1t2.c1)
                           ->  Index Only Scan using t1_i1 on t1 b1t1  (cost=0.28..44.27 rows=1000 width=4)
                           ->  Sort  (cost=59.88..59.89 rows=1 width=12)
                                 Sort Key: b1t2.c1
                                 ->  Nested Loop  (cost=35.57..59.87 rows=1 width=12)
                                       ->  Hash Join  (cost=35.42..59.70 rows=1 width=8)
                                             Hash Cond: (b1t3.c1 = b1t4.c1)
                                             ->  Seq Scan on t3 b1t3  (cost=0.00..21.30 rows=1130 width=4)
                                             ->  Hash  (cost=21.30..21.30 rows=1130 width=4)
                                                   ->  Seq Scan on t4 b1t4  (cost=0.00..21.30 rows=1130 width=4)
                                       ->  Index Only Scan using t2_i1 on t2 b1t2  (cost=0.14..0.17 rows=1 width=4)
                                             Index Cond: (c1 = b1t3.c1)
                     ->  Index Only Scan using t1_i1 on t1 bmt1  (cost=0.28..0.34 rows=1 width=4)
                           Index Cond: (c1 = b1t1.c1)
                           Filter: (c1 <> $3)
               ->  Sort  (cost=5.32..5.57 rows=100 width=4)
                     Sort Key: bmt2.c1
                     ->  Seq Scan on t2 bmt2  (cost=0.00..2.00 rows=100 width=4)
         ->  Index Only Scan using t3_i1 on t3 bmt3  (cost=0.15..0.21 rows=1 width=4)
               Index Cond: (c1 = bmt1.c1)
   ->  Index Only Scan using t4_i1 on t4 bmt4  (cost=0.15..0.21 rows=1 width=4)
         Index Cond: (c1 = bmt1.c1)
(56 rows)

Expected Plans (generated with additional hints)
------------------------------------------------
                                      QUERY PLAN                                                     
--------------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=190.53..217.57 rows=10 width=8)
   Join Filter: (bmt1.c1 = bmt4.c1)
   InitPlan 1 (returns $1)
     ->  Merge Join  (cost=60.16..64.83 rows=1 width=4)
           Merge Cond: (b2t1.c1 = b2t2.c1)
           ->  Index Only Scan using t1_i1 on t1 b2t1  (cost=0.28..44.27 rows=1000 width=4)
           ->  Sort  (cost=59.88..59.89 rows=1 width=12)
                 Sort Key: b2t2.c1
                 ->  Nested Loop  (cost=35.57..59.87 rows=1 width=12)
                       ->  Hash Join  (cost=35.42..59.70 rows=1 width=8)
                             Hash Cond: (b2t3.c1 = b2t4.c1)
                             ->  Seq Scan on t3 b2t3  (cost=0.00..21.30 rows=1130 width=4)
                             ->  Hash  (cost=21.30..21.30 rows=1130 width=4)
                                   ->  Seq Scan on t4 b2t4  (cost=0.00..21.30 rows=1130 width=4)
                       ->  Index Only Scan using t2_i1 on t2 b2t2  (cost=0.14..0.17 rows=1 width=4)
                             Index Cond: (c1 = b2t3.c1)
   InitPlan 2 (returns $3)
     ->  Merge Join  (cost=60.16..64.83 rows=1 width=4)
           Merge Cond: (b3t1.c1 = b3t2.c1)
           ->  Index Only Scan using t1_i1 on t1 b3t1  (cost=0.28..44.27 rows=1000 width=4)
           ->  Sort  (cost=59.88..59.89 rows=1 width=12)
                 Sort Key: b3t2.c1
                 ->  Nested Loop  (cost=35.57..59.87 rows=1 width=12)
                       ->  Hash Join  (cost=35.42..59.70 rows=1 width=8)
                             Hash Cond: (b3t3.c1 = b3t4.c1)
                             ->  Seq Scan on t3 b3t3  (cost=0.00..21.30 rows=1130 width=4)
                             ->  Hash  (cost=21.30..21.30 rows=1130 width=4)
                                   ->  Seq Scan on t4 b3t4  (cost=0.00..21.30 rows=1130 width=4)
                       ->  Index Only Scan using t2_i1 on t2 b3t2  (cost=0.14..0.17 rows=1 width=4)
                             Index Cond: (c1 = b3t3.c1)
   ->  Nested Loop  (cost=60.73..85.70 rows=10 width=28)
         Join Filter: (bmt1.c1 = bmt3.c1)
         ->  Nested Loop  (cost=60.58..83.48 rows=10 width=24)
               Join Filter: (bmt1.c1 = bmt2.c1)
               ->  Nested Loop  (cost=60.43..65.17 rows=100 width=20)
                     Join Filter: (bmt1.c1 = b1t1.c1)
                     ->  Merge Join  (cost=60.16..64.83 rows=1 width=16)
                           Merge Cond: (b1t1.c1 = b1t2.c1)
                           ->  Index Only Scan using t1_i1 on t1 b1t1  (cost=0.28..44.27 rows=1000 width=4)
                           ->  Sort  (cost=59.88..59.89 rows=1 width=12)
                                 Sort Key: b1t2.c1
                                 ->  Nested Loop  (cost=35.57..59.87 rows=1 width=12)
                                       ->  Hash Join  (cost=35.42..59.70 rows=1 width=8)
                                             Hash Cond: (b1t3.c1 = b1t4.c1)
                                             ->  Seq Scan on t3 b1t3  (cost=0.00..21.30 rows=1130 width=4)
                                             ->  Hash  (cost=21.30..21.30 rows=1130 width=4)
                                                   ->  Seq Scan on t4 b1t4  (cost=0.00..21.30 rows=1130 width=4)
                                       ->  Index Only Scan using t2_i1 on t2 b1t2  (cost=0.14..0.17 rows=1 width=4)
                                             Index Cond: (c1 = b1t3.c1)
                     ->  Index Only Scan using t1_i1 on t1 bmt1  (cost=0.28..0.33 rows=1 width=4)
                           Index Cond: (c1 = b1t3.c1)
                           Filter: (c1 <> $3)
               ->  Index Only Scan using t2_i1 on t2 bmt2  (cost=0.14..0.17 rows=1 width=4)
                     Index Cond: (c1 = b1t3.c1)
         ->  Index Only Scan using t3_i1 on t3 bmt3  (cost=0.15..0.21 rows=1 width=4)
               Index Cond: (c1 = b1t3.c1)
   ->  Index Only Scan using t4_i1 on t4 bmt4  (cost=0.15..0.21 rows=1 width=4)
         Index Cond: (c1 = bmt3.c1)
(58 rows)
---------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------
Q5
--
/*+
Leading(c1 bmt4 bmt3 bmt2 bmt1)
Leading(b1t4 b1t3 b1t2 b1t1)
MergeJoin(c1 bmt4)
HashJoin(c1 bmt4 bmt3)
NestLoop(c1 bmt4 bmt3 bmt2)
MergeJoin(c1 bmt4 bmt3 bmt2 bmt1)
MergeJoin(b1t4 b1t3)
HashJoin(b1t4 b1t3 b1t2)
NestLoop(b1t4 b1t3 b1t2 b1t1)
*/
EXPLAIN
WITH c1 (c1) AS (
SELECT b1t1.c1 FROM s1.t1 b1t1, s1.t2 b1t2, s1.t3 b1t3, s1.t4 b1t4 WHERE b1t1.c1 = b1t2.c1 AND b1t1.c1 = b1t3.c1 AND b1t1.c1 = b1t4.c1
)
SELECT bmt1.c1, (
SELECT b2t1.c1 FROM s1.t1 b2t1 WHERE b2t1.c1 = 1
)
                    FROM s1.t1 bmt1, s1.t2 bmt2, s1.t3 bmt3, s1.t4 bmt4, c1 WHERE bmt1.c1 = bmt2.c1 AND bmt1.c1 = bmt3.c1 AND bmt1.c1 = bmt4.c1 AND bmt1.c1 = c1.c1
AND bmt1.c1 <> (
SELECT b3t1.c1 FROM s1.t1 b3t1
);

Actual Plan
-----------
                                      QUERY PLAN                                                          
------------------------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=34.02..213.39 rows=10 width=8)
   InitPlan 1 (returns $0)
     ->  Index Only Scan using t1_i1 on t1 b2t1  (cost=0.28..8.29 rows=1 width=4)
           Index Cond: (c1 = 1)
   InitPlan 2 (returns $1)
     ->  Seq Scan on t1 b3t1  (cost=0.00..16.00 rows=1000 width=4)
   ->  Nested Loop  (cost=9.58..186.95 rows=10 width=28)
         ->  Merge Join  (cost=9.43..184.81 rows=10 width=24)
               Merge Cond: (bmt2.c1 = bmt1.c1)
               ->  Merge Join  (cost=9.15..178.38 rows=100 width=20)
                     Merge Cond: (b1t1.c1 = bmt2.c1)
                     ->  Nested Loop  (cost=3.83..1689.91 rows=100 width=16)
                           Join Filter: (b1t1.c1 = b1t2.c1)
                           ->  Index Only Scan using t1_i1 on t1 b1t1  (cost=0.28..44.27 rows=1000 width=4)
                           ->  Materialize  (cost=3.56..145.88 rows=100 width=12)
                                 ->  Hash Join  (cost=3.56..145.38 rows=100 width=12)
                                       Hash Cond: (b1t3.c1 = b1t2.c1)
                                       ->  Merge Join  (cost=0.30..139.16 rows=1130 width=8)
                                             Merge Cond: (b1t3.c1 = b1t4.c1)
                                             ->  Index Only Scan using t3_i1 on t3 b1t3  (cost=0.15..61.10 rows=1130 width=4)
                                             ->  Index Only Scan using t4_i1 on t4 b1t4  (cost=0.15..61.10 rows=1130 width=4)
                                       ->  Hash  (cost=2.00..2.00 rows=100 width=4)
                                             ->  Seq Scan on t2 b1t2  (cost=0.00..2.00 rows=100 width=4)
                     ->  Sort  (cost=5.32..5.57 rows=100 width=4)
                           Sort Key: bmt2.c1
                           ->  Seq Scan on t2 bmt2  (cost=0.00..2.00 rows=100 width=4)
               ->  Index Only Scan using t1_i1 on t1 bmt1  (cost=0.28..46.77 rows=999 width=4)
                     Filter: (c1 <> $1)
         ->  Index Only Scan using t3_i1 on t3 bmt3  (cost=0.15..0.21 rows=1 width=4)
               Index Cond: (c1 = bmt1.c1)
   ->  Index Only Scan using t4_i1 on t4 bmt4  (cost=0.15..0.21 rows=1 width=4)
         Index Cond: (c1 = bmt1.c1)
(32 rows)

Expected Plans (generated with additional hints)
------------------------------------------------
                                      QUERY PLAN                                                          
------------------------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=28.85..407.03 rows=10 width=8)
   Join Filter: (bmt1.c1 = bmt4.c1)
   InitPlan 1 (returns $0)
     ->  Index Only Scan using t1_i1 on t1 b2t1  (cost=0.28..8.29 rows=1 width=4)
           Index Cond: (c1 = 1)
   InitPlan 2 (returns $1)
     ->  Seq Scan on t1 b3t1  (cost=0.00..16.00 rows=1000 width=4)
   ->  Nested Loop  (cost=4.40..380.53 rows=10 width=28)
         Join Filter: (bmt1.c1 = bmt3.c1)
         ->  Nested Loop  (cost=4.25..378.31 rows=10 width=24)
               Join Filter: (bmt1.c1 = bmt2.c1)
               ->  Nested Loop  (cost=3.97..343.67 rows=100 width=20)
                     Join Filter: (bmt2.c1 = b1t1.c1)
                     ->  Index Only Scan using t2_i1 on t2 bmt2  (cost=0.14..13.64 rows=100 width=4)
                     ->  Materialize  (cost=3.83..180.28 rows=100 width=16)
                           ->  Nested Loop  (cost=3.83..179.78 rows=100 width=16)
                                 Join Filter: (b1t1.c1 = b1t2.c1)
                                 ->  Hash Join  (cost=3.56..145.38 rows=100 width=12)
                                       Hash Cond: (b1t3.c1 = b1t2.c1)
                                       ->  Merge Join  (cost=0.30..139.16 rows=1130 width=8)
                                             Merge Cond: (b1t3.c1 = b1t4.c1)
                                             ->  Index Only Scan using t3_i1 on t3 b1t3  (cost=0.15..61.10 rows=1130 width=4)
                                             ->  Index Only Scan using t4_i1 on t4 b1t4  (cost=0.15..61.10 rows=1130 width=4)
                                       ->  Hash  (cost=2.00..2.00 rows=100 width=4)
                                             ->  Seq Scan on t2 b1t2  (cost=0.00..2.00 rows=100 width=4)
                                 ->  Index Only Scan using t1_i1 on t1 b1t1  (cost=0.28..0.33 rows=1 width=4)
                                       Index Cond: (c1 = b1t3.c1)
               ->  Index Only Scan using t1_i1 on t1 bmt1  (cost=0.28..0.33 rows=1 width=4)
                     Index Cond: (c1 = b1t3.c1)
                     Filter: (c1 <> $1)
         ->  Index Only Scan using t3_i1 on t3 bmt3  (cost=0.15..0.21 rows=1 width=4)
               Index Cond: (c1 = b1t3.c1)
   ->  Index Only Scan using t4_i1 on t4 bmt4  (cost=0.15..0.21 rows=1 width=4)
         Index Cond: (c1 = bmt3.c1)
(34 rows)
---------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------
Q6
--
/*+
Leading(c1 bmt4 bmt3 bmt2 bmt1)
Leading(b1t4 b1t3 b1t2 b1t1)
MergeJoin(c1 bmt4)
HashJoin(c1 bmt4 bmt3)
NestLoop(c1 bmt4 bmt3 bmt2)
MergeJoin(c1 bmt4 bmt3 bmt2 bmt1)
MergeJoin(b1t4 b1t3)
HashJoin(b1t4 b1t3 b1t2)
NestLoop(b1t4 b1t3 b1t2 b1t1)
Rows(c1 bmt4 #1)
Rows(c1 bmt4 bmt3 #1)
Rows(c1 bmt4 bmt3 bmt2 #1)
Rows(c1 bmt4 bmt3 bmt2 bmt1 #1)
Rows(b1t4 b1t3 #1)
Rows(b1t4 b1t3 b1t2 #1)
Rows(b1t4 b1t3 b1t2 b1t1 #1)
*/
EXPLAIN
WITH c1 (c1) AS (
SELECT b1t1.c1 FROM s1.t1 b1t1, s1.t2 b1t2, s1.t3 b1t3, s1.t4 b1t4 WHERE b1t1.c1 = b1t2.c1 AND b1t1.c1 = b1t3.c1 AND b1t1.c1 = b1t4.c1
)
SELECT bmt1.c1, (
SELECT b2t1.c1 FROM s1.t1 b2t1 WHERE b2t1.c1 = 1
)
                    FROM s1.t1 bmt1, s1.t2 bmt2, s1.t3 bmt3, s1.t4 bmt4, c1 WHERE bmt1.c1 = bmt2.c1 AND bmt1.c1 = bmt3.c1 AND bmt1.c1 = bmt4.c1 AND bmt1.c1 = c1.c1
AND bmt1.c1 <> (
SELECT b3t1.c1 FROM s1.t1 b3t1
);

Actual Plan
-----------
                                      QUERY PLAN                                                       
------------------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=31.95..175.18 rows=10 width=8)
   InitPlan 1 (returns $0)
     ->  Index Only Scan using t1_i1 on t1 b2t1  (cost=0.28..8.29 rows=1 width=4)
           Index Cond: (c1 = 1)
   InitPlan 2 (returns $1)
     ->  Seq Scan on t1 b3t1  (cost=0.00..16.00 rows=1000 width=4)
   ->  Nested Loop  (cost=7.51..148.74 rows=10 width=28)
         ->  Hash Join  (cost=7.36..146.60 rows=10 width=24)
               Hash Cond: (bmt1.c1 = bmt2.c1)
               ->  Nested Loop  (cost=4.11..143.09 rows=100 width=20)
                     ->  Nested Loop  (cost=3.83..142.75 rows=1 width=16)
                           Join Filter: (b1t1.c1 = b1t2.c1)
                           ->  Hash Join  (cost=3.56..142.41 rows=1 width=12)
                                 Hash Cond: (b1t3.c1 = b1t2.c1)
                                 ->  Merge Join  (cost=0.30..139.16 rows=1 width=8)
                                       Merge Cond: (b1t3.c1 = b1t4.c1)
                                       ->  Index Only Scan using t3_i1 on t3 b1t3  (cost=0.15..61.10 rows=1130 width=4)
                                       ->  Index Only Scan using t4_i1 on t4 b1t4  (cost=0.15..61.10 rows=1130 width=4)
                                 ->  Hash  (cost=2.00..2.00 rows=100 width=4)
                                       ->  Seq Scan on t2 b1t2  (cost=0.00..2.00 rows=100 width=4)
                           ->  Index Only Scan using t1_i1 on t1 b1t1  (cost=0.28..0.33 rows=1 width=4)
                                 Index Cond: (c1 = b1t3.c1)
                     ->  Index Only Scan using t1_i1 on t1 bmt1  (cost=0.28..0.34 rows=1 width=4)
                           Index Cond: (c1 = b1t1.c1)
                           Filter: (c1 <> $1)
               ->  Hash  (cost=2.00..2.00 rows=100 width=4)
                     ->  Seq Scan on t2 bmt2  (cost=0.00..2.00 rows=100 width=4)
         ->  Index Only Scan using t3_i1 on t3 bmt3  (cost=0.15..0.21 rows=1 width=4)
               Index Cond: (c1 = bmt1.c1)
   ->  Index Only Scan using t4_i1 on t4 bmt4  (cost=0.15..0.21 rows=1 width=4)
         Index Cond: (c1 = bmt1.c1)
(31 rows)

Expected Plans (generated with additional hints)
------------------------------------------------
                                      QUERY PLAN                                                          
------------------------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=28.85..221.26 rows=10 width=8)
   Join Filter: (bmt1.c1 = bmt4.c1)
   InitPlan 1 (returns $0)
     ->  Index Only Scan using t1_i1 on t1 b2t1  (cost=0.28..8.29 rows=1 width=4)
           Index Cond: (c1 = 1)
   InitPlan 2 (returns $1)
     ->  Seq Scan on t1 b3t1  (cost=0.00..16.00 rows=1000 width=4)
   ->  Nested Loop  (cost=4.40..194.75 rows=10 width=28)
         Join Filter: (bmt1.c1 = bmt3.c1)
         ->  Nested Loop  (cost=4.25..192.54 rows=10 width=24)
               Join Filter: (bmt1.c1 = bmt2.c1)
               ->  Nested Loop  (cost=3.97..157.90 rows=100 width=20)
                     Join Filter: (bmt2.c1 = b1t1.c1)
                     ->  Index Only Scan using t2_i1 on t2 bmt2  (cost=0.14..13.64 rows=100 width=4)
                     ->  Materialize  (cost=3.83..142.76 rows=1 width=16)
                           ->  Nested Loop  (cost=3.83..142.75 rows=1 width=16)
                                 Join Filter: (b1t1.c1 = b1t2.c1)
                                 ->  Hash Join  (cost=3.56..142.41 rows=1 width=12)
                                       Hash Cond: (b1t3.c1 = b1t2.c1)
                                       ->  Merge Join  (cost=0.30..139.16 rows=1 width=8)
                                             Merge Cond: (b1t3.c1 = b1t4.c1)
                                             ->  Index Only Scan using t3_i1 on t3 b1t3  (cost=0.15..61.10 rows=1130 width=4)
                                             ->  Index Only Scan using t4_i1 on t4 b1t4  (cost=0.15..61.10 rows=1130 width=4)
                                       ->  Hash  (cost=2.00..2.00 rows=100 width=4)
                                             ->  Seq Scan on t2 b1t2  (cost=0.00..2.00 rows=100 width=4)
                                 ->  Index Only Scan using t1_i1 on t1 b1t1  (cost=0.28..0.33 rows=1 width=4)
                                       Index Cond: (c1 = b1t3.c1)
               ->  Index Only Scan using t1_i1 on t1 bmt1  (cost=0.28..0.33 rows=1 width=4)
                     Index Cond: (c1 = b1t3.c1)
                     Filter: (c1 <> $1)
         ->  Index Only Scan using t3_i1 on t3 bmt3  (cost=0.15..0.21 rows=1 width=4)
               Index Cond: (c1 = b1t3.c1)
   ->  Index Only Scan using t4_i1 on t4 bmt4  (cost=0.15..0.21 rows=1 width=4)
         Index Cond: (c1 = bmt3.c1)
(34 rows)

@HennyNile
Copy link
Author

HennyNile commented Nov 16, 2024

Hi, the generated different plans with the above modifications are due to the plan comparison function compare_path_costs_fuzzily(). This function takes the plans with cost differences in a certain range as the same cost plans, the range is determined by STD_FUZZ_FACTOR (default value is 1.01).For two plans A and B, suppose the cost of plan A is 100, and if B's cost is in the range of 99 and 101, the function compare_path_costs_fuzzily() will take them with the equal cost and save both paths and order them in other metrics.

In our case, if plan A and B are disabled paths and their actual cost are 1e7 and 2e7 respectively, then the planner will add disable_cost to their cost, and the final cost of plan A and B is 1.001e7 and 1.002e7, the function compare_path_costs_fuzzily() will take the plans with the equal cost. However, they have great cost difference.

I think we should add disable_cost to the estimated cost, as fewer cases as better.

Looking forward to a reply.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant