oracle outer join on和where执行顺序:
外连接是以主表数据为基准的,从表没有匹配ON条件的则从表列都置NULL,如果从表有WHERE条件但是不是XX IS NULL或XX(+) IS NULL的,
是正常的不带+的条件,则外连接转为内连接。
ON是外连接关联条件,WHERE是主表过滤或访问条件,主表是先执行WHERE,然后执行ON,
WHERE里也可以增加从表列 IS NULL,从表列IS NULL 这个是外连接后过滤的,从表是先执行ON再执行XX IS NULL。
从表ON里有过滤条件的,也可以先执行,相当于写成inline view,然后执行外连接
1.where条件如果是主表的条件,则主表先过滤,on从表有过滤条件的实际上也可以先过滤,然后再外连接关联
select *
from t1 left join t2
on t1.object_id=t2.object_id and t2.object_name like 'T%'
where t1.object_id<1000;
Elapsed: 00:00:00.04
Execution Plan
----------------------------------------------------------
Plan hash value: 2122192450
---------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 897 | 218K| 36 (6)| 00:00:01 |
|* 1 | HASH JOIN RIGHT OUTER | | 897 | 218K| 36 (6)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| T2 | 11 | 1287 | 10 (20)| 00:00:01 |
| 3 | BITMAP CONVERSION TO ROWIDS | | | | | |
| 4 | BITMAP AND | | | | | |
| 5 | BITMAP CONVERSION FROM ROWIDS | | | | | |
| 6 | SORT ORDER BY | | | | | |
|* 7 | INDEX RANGE SCAN | IDX122 | 992 | | 2 (0)| 00:00:01 |
| 8 | BITMAP CONVERSION FROM ROWIDS | | | | | |
| 9 | SORT ORDER BY | | | | | |
|* 10 | INDEX RANGE SCAN | IDX_T2_OBJECT_ID | 992 | | 3 (0)| 00:00:01 |
| 11 | TABLE ACCESS BY INDEX ROWID BATCHED| T1 | 897 | 115K| 26 (0)| 00:00:01 |
|* 12 | INDEX RANGE SCAN | IDX_T1_OBJECT_ID | 897 | | 5 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID"(+))
7 - access("T2"."OBJECT_NAME"(+) LIKE 'T%')
filter("T2"."OBJECT_NAME"(+) LIKE 'T%' AND "T2"."OBJECT_NAME"(+) LIKE 'T%')
10 - access("T2"."OBJECT_ID"(+)<1000)
filter("T2"."OBJECT_ID"(+)<1000)
12 - access("T1"."OBJECT_ID"<1000)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
171 consistent gets
0 physical reads
0 redo size
72358 bytes sent via SQL*Net to client
1199 bytes received via SQL*Net from client
68 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
995 rows processed
等价改写为:从表过滤条件可以相当于inline view,然后on里只保存join条件
select *
from t1 left join (select t2.* from t2 where t2.object_name like 'T%') t22
on t1.object_id=t22.object_id
where t1.object_id<1000;
2. ON里面有主表过滤条件则比较复杂,因为主表还是按where条件过滤的,这样on里主表过滤条件实际上是完全的
外连接匹配条件,和on里从表过滤条件可以改为inline view不同,主表在on里有过滤条件改不了inline view,
实际上等价于
select *
from t1 left join t2
on t1.object_id=t2.object_id and t1.object_name like 'T%'
;
Elapsed: 00:00:01.88
Execution Plan
----------------------------------------------------------
Plan hash value: 312430291
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 73745 | 17M| 867 (1)| 00:00:01 |
|* 1 | HASH JOIN RIGHT OUTER| | 73745 | 17M| 867 (1)| 00:00:01 |
| 2 | TABLE ACCESS FULL | T2 | 9999 | 1142K| 69 (2)| 00:00:01 |
| 3 | TABLE ACCESS FULL | T1 | 73745 | 9506K| 798 (1)| 00:00:01 |
------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID"(+))
filter("T1"."OBJECT_NAME" LIKE CASE WHEN ("T2"."OBJECT_ID"(+)
IS NOT NULL) THEN 'T%' ELSE 'T%' END )
Statistics
----------------------------------------------------------
28 recursive calls
0 db block gets
7989 consistent gets
3045 physical reads
0 redo size
5136624 bytes sent via SQL*Net to client
54526 bytes received via SQL*Net from client
4918 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
73741 rows processed
-- on里有主表过滤条件
select *
from t1 left join t2
on t1.object_id=t2.object_id and t1.object_name ='T1'
;
等价于
select * from t1, t2
where ("T1"."OBJECT_ID"="T2"."OBJECT_ID"(+) AND
"T1"."OBJECT_NAME"=CASE WHEN ("T2"."OBJECT_ID"(+) IS NOT NULL) THEN
'T1' ELSE 'T1' END );
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/7655508/viewspace-3117890/ ,如需转载,请注明出处,否则将追究法律责任。