no_merge/merge vs no_unnest/unnest

I sometimes get confused about the difference between (no_)merge and(no_)unnest. I just do some test here to make the difference clearly.

The original sql and its plan are below. I’ll hint the sql with no_merge andno_unnest. You will find the difference quickly.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
select * from emp where deptno in (select deptno from dept where dname='SALES');
 
----------------------------------------------------------
Plan hash value: 844388907
 
----------------------------------------------------------------------------------------
| Id  | Operation                    | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |         |     4 |   208 |     6  (17)| 00:02:09 |
|   1 |  MERGE JOIN                  |         |     4 |   208 |     6  (17)| 00:02:09 |
|*  2 |   TABLE ACCESS BY INDEX ROWID| DEPT    |     1 |    13 |     2   (0)| 00:00:43 |
|   3 |    INDEX FULL SCAN           | PK_DEPT |     4 |       |     1   (0)| 00:00:22 |
|*  4 |   SORT JOIN                  |         |    13 |   507 |     4  (25)| 00:01:26 |
|   5 |    TABLE ACCESS FULL         | EMP     |    13 |   507 |     3   (0)| 00:01:05 |
----------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - filter("DNAME"='SALES')
   4 - access("DEPTNO"="DEPTNO")
       filter("DEPTNO"="DEPTNO")

I try the hint no_merge in order to avoid merging the subquery. This obviously don’t work.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
SQL> select * from emp where deptno in (select /*+ no_merge */ deptno from dept where dname='SALES');
 
----------------------------------------------------------
Plan hash value: 844388907
 
----------------------------------------------------------------------------------------
| Id  | Operation                    | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |         |     4 |   208 |     6  (17)| 00:02:09 |
|   1 |  MERGE JOIN                  |         |     4 |   208 |     6  (17)| 00:02:09 |
|*  2 |   TABLE ACCESS BY INDEX ROWID| DEPT    |     1 |    13 |     2   (0)| 00:00:43 |
|   3 |    INDEX FULL SCAN           | PK_DEPT |     4 |       |     1   (0)| 00:00:22 |
|*  4 |   SORT JOIN                  |         |    13 |   507 |     4  (25)| 00:01:26 |
|   5 |    TABLE ACCESS FULL         | EMP     |    13 |   507 |     3   (0)| 00:01:05 |
----------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - filter("DNAME"='SALES')
   4 - access("DEPTNO"="DEPTNO")
       filter("DEPTNO"="DEPTNO")

Then I try the hint no_unnest. It works now. That means (no_)unest works only in the where clause. So I guess (no_)merge is only suitable after the from.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
SQL> select * from emp where deptno in (select /*+ no_unnest */ deptno from dept where dname='SALES');
 
----------------------------------------------------------
Plan hash value: 2809975276
 
----------------------------------------------------------------------------------------
| Id  | Operation            | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT         |         |     4 |   156 |     6   (0)| 00:02:09 |
|*  1 |  FILTER              |         |       |       |        |          |
|   2 |   TABLE ACCESS FULL      | EMP     |    13 |   507 |     3   (0)| 00:01:05 |
|*  3 |   TABLE ACCESS BY INDEX ROWID| DEPT    |     1 |    13 |     1   (0)| 00:00:22 |
|*  4 |    INDEX UNIQUE SCAN         | PK_DEPT |     1 |       |     0   (0)| 00:00:01 |
----------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   1 - filter( EXISTS (SELECT /*+ NO_UNNEST */ 0 FROM "DEPT" "DEPT" WHERE
          "DEPTNO"=:B1 AND "DNAME"='SALES'))
   3 - filter("DNAME"='SALES')
   4 - access("DEPTNO"=:B1)

I do another test with the original sql below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
SQL> select * from emp, (select * from dept where dname = 'SALES') dept where dept.deptno = emp.deptno;
 
----------------------------------------------------------
Plan hash value: 844388907
 
----------------------------------------------------------------------------------------
| Id  | Operation                    | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |         |     4 |   236 |     6  (17)| 00:02:09 |
|   1 |  MERGE JOIN                  |         |     4 |   236 |     6  (17)| 00:02:09 |
|*  2 |   TABLE ACCESS BY INDEX ROWID| DEPT    |     1 |    20 |     2   (0)| 00:00:43 |
|   3 |    INDEX FULL SCAN           | PK_DEPT |     4 |       |     1   (0)| 00:00:22 |
|*  4 |   SORT JOIN                  |         |    13 |   507 |     4  (25)| 00:01:26 |
|   5 |    TABLE ACCESS FULL         | EMP     |    13 |   507 |     3   (0)| 00:01:05 |
----------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - filter("DNAME"='SALES')
   4 - access("DEPT"."DEPTNO"="EMP"."DEPTNO")
       filter("DEPT"."DEPTNO"="EMP"."DEPTNO")

you will see the no_unest hint doesn’t work.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
SQL> select * from emp, (select /*+ no_unnest */ * from dept where dname = 'SALES') dept where dept.deptno = emp.deptno;
 
----------------------------------------------------------
Plan hash value: 844388907
 
----------------------------------------------------------------------------------------
| Id  | Operation                    | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |         |     4 |   236 |     6  (17)| 00:02:09 |
|   1 |  MERGE JOIN                  |         |     4 |   236 |     6  (17)| 00:02:09 |
|*  2 |   TABLE ACCESS BY INDEX ROWID| DEPT    |     1 |    20 |     2   (0)| 00:00:43 |
|   3 |    INDEX FULL SCAN           | PK_DEPT |     4 |       |     1   (0)| 00:00:22 |
|*  4 |   SORT JOIN                  |         |    13 |   507 |     4  (25)| 00:01:26 |
|   5 |    TABLE ACCESS FULL         | EMP     |    13 |   507 |     3   (0)| 00:01:05 |
----------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - filter("DNAME"='SALES')
   4 - access("DEPT"."DEPTNO"="EMP"."DEPTNO")
       filter("DEPT"."DEPTNO"="EMP"."DEPTNO")

Now I hint the original sql with the hint no_merge. It works. That’s it!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
SQL> select * from emp, (select /*+ no_merge */ * from dept where dname = 'SALES') dept where dept.deptno = emp.deptno;
 
----------------------------------------------------------
Plan hash value: 2910064727
 
----------------------------------------------------------------------------
| Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |     4 |   276 |     7  (15)| 00:02:19 |
|*  1 |  HASH JOIN          |      |     4 |   276 |     7  (15)| 00:02:19 |
|   2 |   VIEW              |      |     1 |    30 |     3   (0)| 00:01:05 |
|*  3 |    TABLE ACCESS FULL| DEPT |     1 |    20 |     3   (0)| 00:01:05 |
|   4 |   TABLE ACCESS FULL | EMP  |    13 |   507 |     3   (0)| 00:01:05 |
----------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   1 - access("DEPT"."DEPTNO"="EMP"."DEPTNO")
   3 - filter("DNAME"='SALES')
{'message': "line 1:1: mismatched input 'ads_member_ent_bonus_income_detail_month_z'. Expecting: 'ALTER', 'ANALYZE', 'CALL', 'COMMENT', 'COMMIT', 'CREATE', 'DEALLOCATE', 'DELETE', 'DENY', 'DESC', 'DESCRIBE', 'DROP', 'EXECUTE', 'EXPLAIN', 'GRANT', 'INSERT', 'MERGE', 'PREPARE', 'REFRESH', 'RESET', 'REVOKE', 'ROLLBACK', 'SET', 'SHOW', 'START', 'TRUNCATE', 'UPDATE', 'USE', <query>", 'errorCode': 1, 'errorName': 'SYNTAX_ERROR', 'errorType': 'USER_ERROR', 'errorLocation': {'lineNumber': 1, 'columnNumber': 1}, 'failureInfo': {'type': 'io.trino.sql.parser.ParsingException', 'message': "line 1:1: mismatched input 'ads_member_ent_bonus_income_detail_month_z'. Expecting: 'ALTER', 'ANALYZE', 'CALL', 'COMMENT', 'COMMIT', 'CREATE', 'DEALLOCATE', 'DELETE', 'DENY', 'DESC', 'DESCRIBE', 'DROP', 'EXECUTE', 'EXPLAIN', 'GRANT', 'INSERT', 'MERGE', 'PREPARE', 'REFRESH', 'RESET', 'REVOKE', 'ROLLBACK', 'SET', 'SHOW', 'START', 'TRUNCATE', 'UPDATE', 'USE', <query>", 'cause': {'type': 'org.antlr.v4.runtime.InputMismatchException', 'suppressed': [], 'stack': ['org.antlr.v4.runtime.DefaultErrorStrategy.sync(DefaultErrorStrategy.java:270)', 'io.trino.sql.parser.SqlBaseParser.statement(SqlBaseParser.java:2505)', 'io.trino.sql.parser.SqlBaseParser.singleStatement(SqlBaseParser.java:301)', 'io.trino.sql.parser.SqlParser.invokeParser(SqlParser.java:145)', 'io.trino.sql.parser.SqlParser.createStatement(SqlParser.java:85)', 'io.trino.execution.QueryPreparer.prepareQuery(QueryPreparer.java:55)', 'io.trino.dispatcher.DispatchManager.createQueryInternal(DispatchManager.java:180)', 'io.trino.dispatcher.DispatchManager.lambda$createQuery$0(DispatchManager.java:149)', 'io.trino.$gen.Trino_381____20241206_082905_2.run(Unknown Source)', 'java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)', 'java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)', 'java.base/java.lang.Thread.run(Thread.java:829)']}, 'suppressed': [], 'stack': ['io.trino.s
最新发布
03-21
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值