首先來看兩個sql,返回結果相同,但是耗時差別很大
SQL> select count(*)
2 fromjustin_good r
3 where notexists
4 (select 'x' from justin_count pc where pc.id =r.justin_good_id)
5 ;
COUNT(*)
----------
7229
Executed in 3.437 seconds
SQL> select count(*)
2 fromjustin_good r
3 wherer.justin_good_id not in
4 (select pc.id from justin_count pc)
5 ;
COUNT(*)
----------
7229
Executed in 128.203 seconds
再來看一下它們的執行計劃
使用not exist的語句cost爲3452,而not
in 的卻達到14216
SQL> explain plan for select count(*)
2 fromjustin_good r
3 where notexists
4 (select 'x' from justin_count pc where pc.id =r.justin_good_id);
Explained.
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------------
Plan hash value: 1087925722
Id |
Operation |
Name |
Rows |
Bytes |
Cost(%CPU) |
Time |
0 |
SELECT STATEMENT |
|
1 |
9 |
3452(2) |
00:00:42 |
1 |
SORT AGGREGATE |
|
1 |
9 |
|
|
2 |
HASH JOIN RIGHT ANTI |
|
59 |
531 |
3452(2) |
00:00:42 |
3 |
INDEX FAST FULL SCAN |
PK11_1 |
4562 |
22810 |
4(0) |
00:00:01 |
4 |
TABLE ACCESS FULL |
justin_good |
602K |
2355K |
3440(2) |
00:00:42 |
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 -access("PC"."ID"="R"."justin_good_id")
16 rows selected.
SQL> explain plan for select count(*)
2 fromjustin_good r
3 wherer.justin_good_id not in
4 (select pc.id from justin_count pc);
Explained.
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------------Planhash value: 4119029611
Id |
Operation |
Name |
Rows |
Bytes |
Cost(%CPU) |
Time |
0 |
SELECT STATEMENT |
|
1 |
4 |
14216 (2) |
00:00:42 |
1 |
SORT AGGREGATE |
|
1 |
4 |
|
|
2 |
FILTER |
|
|
|
|
00:00:42 |
3 |
TABLE ACCESS FULL |
PK11_1 |
602K |
2355K |
3442 (2) |
00:00:01 |
4 |
INDEX FULL SCAN |
justin_good |
1 |
5 |
11 (0) |
00:00:42 |
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter( NOT EXISTS (SELECT 0 FROM "justin"."justin_count""PC" WHERE
LNNVL("PC"."ID"<>:B1)))
4 - filter(LNNVL("PC"."ID"<>:B1))
18 rows selected.
當使用 where a not in (select …)的時候,必須確保該列a的返回值沒有null,否則無法進行hash
join anti.
解決辦法:
1、 爲該列加not null約束
2、 改寫sql,如not exists
當oracle解析where a not in (select )之類的sql時,會查看列a是否存在null,只有當確保不存在的時候,纔會考慮將Not in轉換爲anti-join;然後進行一系列諸如nest loop join,merge join的cost對比,最終敲定執行計劃