首先来看两个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对比,最终敲定执行计划