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'
)
|