当SQL语句中包含in语句时,有时候会极大的影响性能,我们可以把in子查询用exists子查询或外连接替代:
例子如下:
1.SQL语句中包含IN子查询:
SQL> select * from servers s
2 where s.srvr_id = 3333333 or
3 s.srvr_id in (select t.srvr_id
4 from serv_inst t
5 where t.si_status = 'Activated'
6 and t.type = 'UNIX')
7 /
已选择11行。
执行计划
----------------------------------------------------------
Plan hash value: 910321333
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 6 | 378 | 2 (0)| 00:00:01 |
|* 1 | FILTER | | | | | |
| 2 | TABLE ACCESS FULL| SERVERS | 96 | 6048 | 2 (0)| 00:00:01 |
|* 3 | TABLE ACCESS FULL| SERV_INST | 2 | 38 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("S"."SRVR_ID"=3333333 OR EXISTS (SELECT /*+ */ 0 FROM
"SERV_INST" "T" WHERE "T"."SRVR_ID"=:B1 AND "T"."SI_STATUS"='Activated'
AND "T"."TYPE"='UNIX'))
3 - filter("T"."SRVR_ID"=:B1 AND "T"."SI_STATUS"='Activated' AND
"T"."TYPE"='UNIX')
Note
-----
- dynamic sampling used for this statement
统计信息
----------------------------------------------------------
0 recursive calls
0 db block gets
818 consistent gets
0 physical reads
0 redo size
1146 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
11 rows processed
SQL>
2.把上面SQL语句改为EXISTS子查询形式
SQL> select *
2 from servers s
3 where s.srvr_id = 3333333 or exists (select 1
4 from serv_inst t
5 where s.srvr_id = t.srvr_id
6 and t.si_status = 'Activated'
7 and t.type = 'UNIX')
8 /
已选择11行。
执行计划
----------------------------------------------------------
Plan hash value: 910321333
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 6 | 378 | 2 (0)| 00:00:01 |
|* 1 | FILTER | | | | | |
| 2 | TABLE ACCESS FULL| SERVERS | 96 | 6048 | 2 (0)| 00:00:01 |
|* 3 | TABLE ACCESS FULL| SERV_INST | 2 | 38 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("S"."SRVR_ID"=3333333 OR EXISTS (SELECT /*+ */ 0 FROM
"SERV_INST" "T" WHERE "T"."SRVR_ID"=:B1 AND "T"."SI_STATUS"='Activated'
AND "T"."TYPE"='UNIX'))
3 - filter("T"."SRVR_ID"=:B1 AND "T"."SI_STATUS"='Activated' AND
"T"."TYPE"='UNIX')
Note
-----
- dynamic sampling used for this statement
统计信息
----------------------------------------------------------
0 recursive calls
0 db block gets
818 consistent gets
0 physical reads
0 redo size
1146 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
11 rows processed
SQL>
3.改成另一种外连接的方式
SQL> select distinct s.*
2 from servers s
3 left join serv_inst t on s.srvr_id = t.srvr_id
4 and t.si_status = 'Activated'
5 and t.type = 'UNIX'
6 where ((t.siid is not null) or (t.siid is null and s.srvr_id = 3333333))
7 /
已选择11行。
执行计划
----------------------------------------------------------
Plan hash value: 2837582902
----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 96 | 8448 | 7 (29)| 00:00:01 |
| 1 | HASH UNIQUE | | 96 | 8448 | 7 (29)| 00:00:01 |
|* 2 | FILTER | | | | | |
|* 3 | HASH JOIN OUTER | | 96 | 8448 | 6 (17)| 00:00:01 |
| 4 | TABLE ACCESS FULL| SERVERS | 96 | 6048 | 2 (0)| 00:00:01 |
|* 5 | TABLE ACCESS FULL| SERV_INST | 57 | 1425 | 3 (0)| 00:00:01 |
----------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("T"."SIID" IS NOT NULL OR "T"."SIID" IS NULL AND
"S"."SRVR_ID"=3333333)
3 - access("S"."SRVR_ID"="T"."SRVR_ID"(+))
5 - filter("T"."TYPE"(+)='UNIX' AND "T"."SI_STATUS"(+)='Activated')
Note
-----
- dynamic sampling used for this statement
统计信息
----------------------------------------------------------
0 recursive calls
0 db block gets
12 consistent gets
0 physical reads
0 redo size
1154 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
11 rows processed
SQL>
4.另一种外连接的写法
SQL> select distinct s.*
2 from servers s, serv_inst t
3 where s.srvr_id = t.srvr_id(+)
4 and t.si_status(+) = 'Activated'
5 and t.type(+) = 'UNIX'
6 and ((t.siid is not null) or (t.siid is null and s.srvr_id = 3333333))
7 /
已选择11行。
执行计划
----------------------------------------------------------
Plan hash value: 2837582902
----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 96 | 8448 | 7 (29)| 00:00:01 |
| 1 | HASH UNIQUE | | 96 | 8448 | 7 (29)| 00:00:01 |
|* 2 | FILTER | | | | | |
|* 3 | HASH JOIN OUTER | | 96 | 8448 | 6 (17)| 00:00:01 |
| 4 | TABLE ACCESS FULL| SERVERS | 96 | 6048 | 2 (0)| 00:00:01 |
|* 5 | TABLE ACCESS FULL| SERV_INST | 57 | 1425 | 3 (0)| 00:00:01 |
----------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("T"."SIID" IS NOT NULL OR "T"."SIID" IS NULL AND
"S"."SRVR_ID"=3333333)
3 - access("S"."SRVR_ID"="T"."SRVR_ID"(+))
5 - filter("T"."SI_STATUS"(+)='Activated' AND "T"."TYPE"(+)='UNIX')
Note
-----
- dynamic sampling used for this statement
统计信息
----------------------------------------------------------
0 recursive calls
0 db block gets
12 consistent gets
0 physical reads
0 redo size
1154 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
11 rows processed
SQL>
以上三种方式比较,看来还是用外连接的方式查询效率更高