星型转换在数据仓库中用到。
有人说返回值少的时候用in,返回值多的时候用exists这种说法是不对的。
前面提到过半连接/反连接,当时我说,大家不要去记什么时候用in,exists,not in ,not exists。
子查询非嵌套(subquery unnesting)
在学习subquery unnesting之前,先深入理解 执行计划中的
FILTER
,可以这样说,
绝大部分复杂的子查询,性能问题基本上都是出现在
FILTER上面
。现在举个例子解释一下什么是FILTER。(你们要模拟就自己创建一个test表,数据从dba_objects复制)
点击( 此处 )折叠或打开
SQL
>
select
*
from test1 where owner
=
'SCOTT'
or
object_id
in
(
select object_id from test2 where owner
=
'SCOTT'
)
;
已选择7行。
执行计划
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Plan hash value
:
989345917
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
Id
|
Operation
|
Name
|
Rows
|
Bytes
|
Cost
(
%
CPU
)
|
Time
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
0
|
SELECT STATEMENT
|
|
2529
|
229K
|
163
(
4
)
|
00
:
00
:
02
|
|
*
1
|
FILTER
|
|
|
|
|
|
|
2
|
TABLE ACCESS FULL
|
TEST1
|
50443
|
4581K
|
163
(
4
)
|
00
:
00
:
02
|
|
*
3
|
TABLE ACCESS BY INDEX ROWID
|
TEST2
|
1
|
11
|
2
(
)
|
00
:
00
:
01
|
|
*
4
|
INDEX RANGE SCAN
|
IDX3
|
1
|
|
1
(
)
|
00
:
00
:
01
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Predicate Information
(
identified by operation id
)
:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
1
-
filter
(
"OWNER"
=
'SCOTT'
OR
EXISTS
(
SELECT /
*
+
*
/
0 FROM
"TEST2"
"TEST2"
WHERE
"OBJECT_ID"
=
:
B1
AND
"OWNER"
=
'SCOTT'
)
)
3
-
filter
(
"OWNER"
=
'SCOTT'
)
4
-
access
(
"OBJECT_ID"
=
:
B1
)
统计信息
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
1 recursive calls
0 db block gets
152116 consistent gets
111 physical reads
0 redo
size
1430 bytes sent via SQL
*
Net to client
400 bytes received via SQL
*
Net from client
2 SQL
*
Net roundtrips to/from client
0 sorts
(
memory
)
0 sorts
(
disk
)
7 rows processed
点击( 此处 )折叠或打开
这个SQL语句的特殊执行计划如下:
SQL
>
select
*
from table
(
dbms_xplan
.
display_cursor
(
null
,
null
,
'ALLSTATS LAST'
)
)
;
PLAN_TABLE_OUTPUT
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
SQL_ID a23r1uchdaafg
,
child number 0
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
select
*
from test1 where owner
=
'SCOTT'
or
object_id
in
(
select object_id from test2
where owner
=
'SCOTT'
)
Plan hash value
:
989345917
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
Id
|
Operation
|
Name
|
Starts
|
E
-
Rows
|
A
-
Rows
|
A
-
Time
|
Buffers
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
*
1
|
FILTER
|
|
1
|
|
7
|
00
:
00
:
00
.
25
|
152K
|
|
2
|
TABLE ACCESS FULL
|
TEST1
|
1
|
50443
|
50443
|
00
:
00
:
00
.
01
|
699
|
|
*
3
|
TABLE ACCESS BY INDEX ROWID
|
TEST2
|
50436
|
1
|
0
|
00
:
00
:
00
.
19
|
151K
|
|
*
4
|
INDEX RANGE SCAN
|
IDX3
|
50436
|
1
|
50436
|
00
:
00
:
00
.
12
|
100K
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Predicate Information
(
identified by operation id
)
:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
1
-
filter
(
(
"OWNER"
=
'SCOTT'
OR
IS
NOT
NULL
)
)
3
-
filter
(
"OWNER"
=
'SCOTT'
)
4 - access ( "OBJECT_ID" = : B1 )
--starts 执行的次数
点击(
此处
)折叠或打开
scott@TESTDB12
>
select
*
from test1 where owner
=
'SCOTT'
or
object_id
in
(
select object_id from test2 where owner
=
'SCOTT'
)
;
8 rows selected
.
Execution Plan
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Plan hash value
:
1896454807
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
Id
|
Operation
|
Name
|
Rows
|
Bytes
|
Cost
(
%
CPU
)
|
Time
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
0
|
SELECT STATEMENT
|
|
5078
|
1026K
|
301
(
1
)
|
00
:
00
:
04
|
|
*
1
|
FILTER
|
|
|
|
|
|
|
2
|
TABLE ACCESS FULL
|
TEST1
|
85348
|
16M
|
301
(
1
)
|
00
:
00
:
04
|
|
*
3
|
TABLE ACCESS FULL
|
TEST2
|
1
|
30
|
300
(
1
)
|
00
:
00
:
04
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Predicate Information
(
identified by operation id
)
:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
1
-
filter
(
"OWNER"
=
'SCOTT'
OR
EXISTS
(
SELECT 0 FROM
"TEST2"
"TEST2"
WHERE
"OBJECT_ID"
=
:
B1
AND
"OWNER"
=
'SCOTT'
)
)
3
-
filter
(
"OBJECT_ID"
=
:
B1
AND
"OWNER"
=
'SCOTT'
)
Note
-
-
-
-
-
-
dynamic sampling used
for
this
statement
(
level
=
2
)
Statistics
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
0 recursive calls
0 db block gets
80944276 consistent gets
80718384 physical reads
0 redo
size
1975 bytes sent via SQL
*
Net to client
523 bytes received via SQL
*
Net from client
2 SQL
*
Net roundtrips to/from client
0 sorts
(
memory
)
0 sorts
(
disk
)
8 rows processed
点击(
此处
)折叠或打开
SELECT B
.
AREA_ID
,
A
.
PARTY_ID
,
B
.
AREA_NAME
,
C
.
NAME
CHANNEL_NAME
,
B
.
NAME
PARTY_NAME
,
B
.
ACCESS_NUMBER
,
B
.
PROD_SPEC
,
B
.
START_DT
,
A
.
BO_ACTION_NAME
,
A
.
SO_STAFF_ID
,
A
.
ATOM_ACTION_ID
,
A
.
PROD_ID
FROM DW_CHANNEL C
,
DW_CRM_DAY_USER B
,
DW_BO_ORDER A
WHERE A
.
PROD_ID
=
B
.
PROD_ID
AND
A
.
CHANNEL_ID
=
C
.
CHANNEL_ID
AND
A
.
SO_STAFF_ID LIKE
'36%'
AND
A
.
BO_ACTION_NAME
IN
(
'新装'
,
'移机'
,
'资费变更'
)
AND
B
.
PROD_SPEC
IN
(
'普通电话'
,
'ADSL'
,
'LAN'
,
'手机'
,
'E8 - 2S'
,
'E6移动版'
,
'E9版1M(老版)'
,
'普通E9'
,
'普通新版E8'
,
'全省_紧密融合型E9套餐产品规格'
,
'(新) 全省_紧密融合型E9套餐产品规格'
,
'新春欢乐送之E8套餐'
,
'新春欢乐送之E6套餐'
)
AND
NOT
EXISTS
(
SELECT
*
FROM DW_BO_ORDER D
WHERE D
.
STAFF_ID LIKE
'36%'
AND
A
.
PARTY_ID
=
D
.
PARTY_ID
AND
A
.
BO_ID
!
=
D
.
BO_ID
AND
A
.
PROD_ID
!
=
D
.
PROD_ID
AND
A
.
BO_ACTION_NAME
IN
(
'新装'
,
\
'移机'
,
'资费变更'
)
AND
A
.
COMPLETE_DT
-
INTERVAL
'7'
DAY
<
D
.
COMPLETE_DT
);
点击(
此处
)折叠或打开
SQL
>
select count
(
*
)
from dw_bo_order
;
COUNT
(
*
)
-
-
-
-
-
-
-
-
-
-
2282548
SQL
>
select count
(
*
)
from dw_crm_day_user
;
COUNT
(
*
)
-
-
-
-
-
-
-
-
-
-
420918
SQL
>
select count
(
*
)
from dw_channel
;
COUNT
(
*
)
-
-
-
-
-
-
-
-
-
-
48031
点击(
此处
)折叠或打开
Plan hash value
:
2142862569
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
Id
|
Operation
|
Name
|
Rows
|
Bytes
|
Cost
(
%
CPU
)
|
Time
|
Pstart
|
Pstop
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
0
|
SELECT STATEMENT
|
|
905
|
121K
|
4152K
(
2
)
|
13
:
50
:
32
|
|
|
|
*
1
|
FILTER
|
|
|
|
|
|
|
|
|
*
2
|
HASH JOIN
|
|
905
|
121K
|
12616
(
2
)
|
00
:
02
:
32
|
|
|
|
*
3
|
HASH JOIN
|
|
905
|
99550
|
12448
(
2
)
|
00
:
02
:
30
|
|
|
|
4
|
PARTITION RANGE ALL
|
|
1979
|
108K
|
9168
(
2
)
|
00
:
01
:
51
|
1
|
5
|
|
*
5
|
TABLE ACCESS FULL
|
DW_BO_ORDER
|
1979
|
108K
|
9168
(
2
)
|
00
:
01
:
51
|
1
|
5
|
|
*
6
|
TABLE ACCESS FULL
|
DW_CRM_DAY_USER
|
309K
|
15M
|
3277
(
2
)
|
00
:
00
:
40
|
|
|
|
7
|
TABLE ACCESS FULL
|
DW_CHANNEL
|
48425
|
1276K
|
168
(
1
)
|
00
:
00
:
03
|
|
|
|
*
8
|
FILTER
|
|
|
|
|
|
|
|
|
9
|
PARTITION RANGE ALL
|
|
1
|
29
|
9147
(
2
)
|
00
:
01
:
50
|
1
|
5
|
|
*
10
|
TABLE ACCESS FULL
|
DW_BO_ORDER
|
1
|
29
|
9147
(
2
)
|
00
:
01
:
50
|
1
|
5
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Predicate Information
(
identified by operation id
)
:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
1
-
filter
(
NOT
EXISTS
(
SELECT /
*
+
*
/
0 FROM
"DW_BO_ORDER"
"D"
WHERE
(
:
B1
=
'新装'
OR
:
B2
=
'移机'
OR
:
B3
=
'资费变更'
)
AND
"D"
.
"PARTY_ID"
=
:
B4
AND
TO_CHAR
(
"D"
.
"STAFF_ID"
)
LIKE
'36%'
AND
"D"
.
"COMPLETE_DT"
>
:
B5
-
INTERVAL
'+07 00:00:00'
DAY
(
2
)
TO SECOND
(
)
AND
"D"
.
"PROD_ID"
<
>
:
B6
AND
"D"
.
"BO_ID"
<
>
:
B7
)
)
2
-
access
(
"A"
.
"CHANNEL_ID"
=
"C"
.
"CHANNEL_ID"
)
3
-
access
(
"A"
.
"PROD_ID"
=
"B"
.
"PROD_ID"
)
5
-
filter
(
"A"
.
"PROD_ID"
IS
NOT
NULL
AND
(
"A"
.
"BO_ACTION_NAME"
=
'新装'
OR
"A"
.
"BO_ACTION_NAME"
=
'移机'
OR
"A"
.
"BO_ACTION_NAME"
=
'资费变更'
)
AND
TO_CHAR
(
"A"
.
"SO_STAFF_ID"
)
LIKE
'36%'
)
6
-
filter
(
"B"
.
"PROD_SPEC"
=
'(新) 全省_紧密融合型E9套餐产品规格'
OR
"B"
.
"PROD_SPEC"
=
'ADSL'
OR
"B"
.
"PROD_SPEC\"
=
'E6移动版'
OR
"B"
.
"PROD_SPEC"
=
'E8 - 2S'
OR
"B"
.
"PROD_SPEC"
=
'E9版1M(老版)'
OR
"B"
.
"PROD_SPEC"
=
'LAN'
OR
"B"
.
"PROD_SPEC"
=
'普通E9'
OR
"B"
.
"PROD_SPEC"
=
'普通电话'
OR
"B"
.
"PROD_SPEC"
=
'普通新版E8'
OR
"B"
.
"PROD_SPEC"
=
'全省_紧密融合型E9套餐产品规格'
OR
"B"
.
"PROD_SPEC"
=
'手机'
OR
"B"
.
"PROD_SPEC"
=
'新春欢乐送之E6套餐'
OR
"B"
.
"PROD_SPEC"
=
'新春欢乐送之E8套餐'
)
8
-
filter
(
:
B1
=
'新装'
OR
:
B2
=
'移机'
OR
:
B3
=
'资费变更'
)
10
-
filter
(
"D"
.
"PARTY_ID"
=
:
B1
AND
TO_CHAR
(
"D"
.
"STAFF_ID"
)
LIKE
'36%'
AND
"D\"
.
"COMPLETE_DT"
>
:
B2
-
INTERVAL
'+07 00:00:00'
DAY
(
2
)
TO SECOND
(
)
AND
"D"
.
"PROD_ID"
<
>
:
B3
AND
"D"
.
"BO_ID"
<
>
:
B4
)
点击(
此处
)折叠或打开
PLAN_TABLE_OUTPUT
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
Id
|
Operation
|
Name
|
Rows
|
Bytes
|
Cost
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
0
|
SELECT STATEMENT
|
|
1
|
81
|
1618
|
|
1
|
SORT AGGREGATE
|
|
1
|
81
|
|
|
*
2
|
FILTER
|
|
|
|
|
|
*
3
|
HASH JOIN OUTER
|
|
|
|
|
|
4
|
NESTED LOOPS OUTER
|
|
642
|
38520
|
838
|
|
*
5
|
INDEX FAST FULL SCAN
|
PK_T_SEND_VEHICLE
|
413
|
8260
|
12
|
|
6
|
TABLE ACCESS BY INDEX ROWID
|
T_TASK_HEAD
|
2
|
80
|
2
|
|
*
7
|
INDEX RANGE SCAN
|
IDX_TASK_VEHICLE_NO
|
2
|
|
1
|
|
8
|
TABLE ACCESS FULL
|
T_TASK_DETAIL
|
162K
|
3337K
|
777
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Predicate Information
(
identified by operation id
)
:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
2
-
filter
(
"TTASKDETAI2_"
.
"IS_REAL"
=
'N'
OR
"TTASKDETAI2_"
.
"IS_REAL"
IS NULL
)
3
-
access
(
"TRANSTASKH0_"
.
"TRANS_TASK_NO"
=
"TTASKDETAI2_"
.
"TRANS_TASK_NO"
(
+
)
)
5
-
filter
(
TRIM
(
"SENDVEHICL1_"
.
"SEND_VEHICLE_NO"
)
=
'01037041212280054'
)
7
-
access
(
"TRANSTASKH0_"
.
"SEND_VEHICLE_NO"
(
+
)
=
"SENDVEHICL1_"
.
"SEND_VEHICLE_NO"
)
点击(
此处
)折叠或打开
select ename
,
deptno from emp where deptno
in
(
select deptno from dept where dname
=
'CHICAGO'
)
;
执行计划如下:
SQL
>
explain plan
for
select ename
,
deptno from emp where deptno
in
(
select deptno from dept where dname
=
'CHICAGO'
)
;
Explained
.
SQL
>
select
*
from table
(
dbms_xplan
.
display
)
;
PLAN_TABLE_OUTPUT
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Plan hash value
:
844388907
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
Id
|
Operation
|
Name
|
Rows
|
Bytes
|
Cost
(
%
CPU
)
|
Time
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
0
|
SELECT STATEMENT
|
|
5
|
110
|
6
(
17
)
|
00
:
00
:
01
|
|
1
|
MERGE JOIN
|
|
5
|
110
|
6
(
17
)
|
00
:
00
:
01
|
|
*
2
|
TABLE ACCESS BY INDEX ROWID
|
DEPT
|
1
|
13
|
2
(
)
|
00
:
00
:
01
|
|
3
|
INDEX FULL SCAN
|
PK_DEPT
|
4
|
|
1
(
)
|
00
:
00
:
01
|
|
*
4
|
SORT JOIN
|
|
14
|
126
|
4
(
25
)
|
00
:
00
:
01
|
|
5
|
TABLE ACCESS FULL
|
EMP
|
14
|
126
|
3
(
)
|
00
:
00
:
01
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Predicate Information
(
identified by operation id
)
:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
2
-
filter
(
"DNAME"
=
'CHICAGO'
)
4
-
access
(
"DEPTNO"
=
"DEPTNO"
)
filter
(
"DEPTNO"
=
"DEPTNO"
)
用hint NO_UNNEST 可以禁止CBO 进行 Subquery Unnesting
hint UNNEST 可以提示CBO进行Subquery Unnesting
点击(
此处
)折叠或打开
select ename
,
deptno from emp where deptno
in
(
select /
*
+
NO_UNNEST
*
/
deptno from dept where dname
=
\
'CHICAGO\'
)
;
SQL
>
select
*
from table
(
dbms_xplan
.
display
)
;
PLAN_TABLE_OUTPUT
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Plan hash value
:
2809975276
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
Id
|
Operation
|
Name
|
Rows
|
Bytes
|
Cost
(
%
CPU
)
|
Time
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
0
|
SELECT STATEMENT
|
|
5
|
45
|
6
(
)
|
00
:
00
:
01
|
|
*
1
|
FILTER
|
|
|
|
|
|
|
2
|
TABLE ACCESS FULL
|
EMP
|
14
|
126
|
3
(
)
|
00
:
00
:
01
|
|
*
3
|
TABLE ACCESS BY INDEX ROWID
|
DEPT
|
1
|
13
|
1
(
)
|
00
:
00
:
01
|
|
*
4
|
INDEX UNIQUE SCAN
|
PK_DEPT
|
1
|
|
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"
=
'CHICAGO'
)
)
3
-
filter
(
"DNAME"
=
'CHICAGO'
)
4
-
access
(
"DEPTNO"
=
:
B1
)
--E-Rows 优化器估算的行数
--A-Rows 实际返回的行数
--A-Time 某个操作执行的时间
--Buffers标示逻辑读
filter其实就相当于 NESTED LOOPS ,但是又不完全是 NESTED LOOPS,nested loop是驱动表返回一行,被驱动表执行一次,但是filter不是这样,你也不必要懂filter的底层原理,你就把filter当成nested loop就行了,
我们拿上面这
个执行计划
为例:id=2这有8万行数据,id=3要被全表扫面接近8万次,
假设id=3这个表有10M数据,那么8w*10MB=800G的数据量需要进行io。nested loop 驱动表返回一行,被驱动表执行一次,但是filter不确定,比如有肯能驱动表返回10w行,被驱动表执行4w次。
主要是看返回表
的NDV,这是小细节了,不用关心。
下面是表的统计:
下面是执行计划
filter我们看有儿子的filter,这个相当于nested loop ,id=8的地方的filter只起到过滤的作用。
以后看到执行计划里有filter菊花一紧。
还有另外一种FILTER,单操作的FILTER,执行计划如下:
下面我们看:
Subquery Unnesting(子查询非嵌套):
如果SQL语句中的where条件后面有子查询,子查询前面有in,not in,exists,not exists,<,<=,=,>,>= 等等,CBO很可能会对该子查询进行等价改写,改写的过程其实就叫做子查询扩展。Oracle始终认为SQL语句进行改写之后,CBO能更好的优化,当然了,并不是所有的子查询都会被改写,子查询中有些限制条件会阻止CBO进行改写(因为改写之后不等价)。
如何才能查看SQL进行了subquery unnesting?
请自己翻阅之前讲解执行计划的章节,这里再提一下,利用下面SQL可以查看到
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'ADVANCED -PROJECTION'));
Disable Subquery Unnesting:
alter session set "_unnest_subquery"=false;
select e.ename,e.deptno from emp e,dept d where e.deptno=d.deptno and d.dname='CHICAGO';
这个sql语句的执行计划和上边的执行计划是一样。
上面HINT只能放在子查询里面
子查询没有被展开,执行计划里会有filter关键字。
id=1 :B1绑定变量,当我传入一个值的时候,id=4的地方就要被扫面一次。
这就是为什么前面说的与nested loop不同的原因了
,如果同样值就不会多次扫描了。
只有半链接和反连接才会发生filter,所以filter返回的数据是主表的数据。
子查询没有展开通常性能比较差,但是也有用filter去优化的。
有filter一定有绑定变量。绑定变量成双成对出现。这个关联的列基本上是主键啦,所以看NDV有没有必要,NDV当然非常高了。
其次看被驱动表是不是全表扫面,如果是,并且表的segments size很大,那就是操蛋了,让被驱动表走索引,要不改sql,要不让他解套。
不是说走filter一定不正常,filter用儿子的情况可能正常,filter没儿子也可能正常。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/29990276/viewspace-1448367/ ,如需转载,请注明出处,否则将追究法律责任。