38
ITPUB2011 技技技技技技技 Something about Oracle Joins 技技 dingjun123 mailto:[email protected]

Something about oracle joins

Embed Size (px)

DESCRIPTION

Oracle,JOIN,SQL,OPTIMIZE

Citation preview

Page 1: Something about oracle joins

ITPUB2011 技术沙龙上海站

Something about Oracle Joins

丁俊 dingjun123mailto:[email protected]

Page 2: Something about oracle joins

ITPUB2011 技术沙龙上海站

内容简介 Oracle Join 简介

– Join 重要性– Join 的类别– Examples

新旧 Join 语法– 理解 SQL86 中的“ +”– 理解 SQL92 的 on 和 where– 何时用新语法– Examples

Page 3: Something about oracle joins

ITPUB2011 技术沙龙上海站

内容简介续 常见 Join 问题和 Tuning

– 关联 update 及优化

– Semi Join 和 Anti Join 注意点

– Set 操作转换

Page 4: Something about oracle joins

ITPUB2011 技术沙龙上海站

Oracle Join 简介 -Join 的重要性 Join 是关系型数据库的核心内容

– Query 中经常使用表连接查询– DML 、 DDL 也经常使用到表连接– Oracle Join 有高效的算法作为性能支撑

Join 无处不在

Page 5: Something about oracle joins

ITPUB2011 技术沙龙上海站

Oracle Join 简介 -Join 的类别 Join 类别

– Inner Join and Outer Join– Equi-Join and Non-Equi-Join– Semi Join and Anti Join– Self join 、 Cross Join…

能够识别 Join 和使用对应的 Join 很重要

Page 6: Something about oracle joins

ITPUB2011 技术沙龙上海站

Oracle Join 简介 -ExamplesNon-equi-Join and self Join Example

SELECT a.ename,b.ename, a.hiredate,b.hiredateFROM scott.emp a,scott.emp bWHERE a.hiredate <= b.hiredateAND a.empno <> b.empno;

……

使用 Non-equi-join 要考虑清楚

Page 7: Something about oracle joins

ITPUB2011 技术沙龙上海站

Oracle Join 简介 -ExamplesSemi Join Example

SELECT a.ename,a.hiredateFROM scott.emp aWHERE EXISTS(SELECT 1 FROM scott.emp b WHERE a.hiredate <= b.hiredate AND a.empno <> b.empno); S

emi jo

in

短路

Q : Semi join 最常见经典应用?A :找结果集是否存在数据

Page 8: Something about oracle joins

ITPUB2011 技术沙龙上海站

Oracle Join 简介 -ExamplesAnti Join Example

SELECT a.ename,a.hiredateFROM scott.emp aWHERE NOT EXISTS(SELECT 1 FROM scott.emp b WHERE a.hiredate <= b.hiredate AND a.empno <> b.empno);

An

ti join

无短路

No matched results,so returned

Page 9: Something about oracle joins

ITPUB2011 技术沙龙上海站

新旧 Join 语法 –理解 SQL86 中的“ +”

Oracle 把我的 + 号吃了?

Table a Table b

right join

SELECT a.ID,a.NAME,a.code, b.ID,b.NAME,b.codeFROM a,bWHERE a.ID(+)=b.ID AND a.NAME(+)=b.NAME AND TO_NUMBER(a.code)=b.code;

注意复杂外连接的写法,不要丢掉 + 号

Page 10: Something about oracle joins

ITPUB2011 技术沙龙上海站

新旧 Join 语法 –理解 SQL86 中的“ +”

加上 + 号后,执行计划为SELECT a.ID,a.NAME,a.code, b.ID,b.NAME,b.codeFROM a,bWHERE a.ID(+)=b.ID AND a.NAME(+)=b.NAMEAND TO_NUMBER(a.code(+))=b.code;

My god!so esay!My god!so easy!

Page 11: Something about oracle joins

ITPUB2011 技术沙龙上海站

新旧 Join 语法 –理解 SQL86 中的“ +”

“+”到底做了什么? If A and B are joined by multiple join conditions, then you must use the (+)operator in all of these conditions. If you do not, then Oracle will return onlythe rows resulting from a simple join, but without a warning or error to adviseyou that you do not have the results of an outer join.

理解文档中的 Join conditions的含义很重要,文档并不详细。可能会导致理解错误:只要 right table 的列漏掉 + 就不是外连接?

Page 12: Something about oracle joins

ITPUB2011 技术沙龙上海站

新旧 Join 语法 –理解 SQL86 中的“ +”

Table a Table bSELECT a.ID,a.NAME,b.ID,b.NAMEFROM a,bWHERE a.ID(+)=b.ID AND a.ID IS NULL; SELECT a.ID,a.NAME,b.ID,b.NAME FROM a,bWHERE a.ID=b.ID AND a.ID IS NULL; SELECT a.ID,a.NAME,b.ID,b.NAMEFROM a,bWHERE a.ID(+)=b.ID AND a.NAME=‘b’; SELECT a.ID,a.NAME,b.ID,b.NAMEFROM a,bWHERE a.ID(+)=b.ID AND a.NAME=b.NAME;

SELECT a.ID,a.NAME,b.ID,b.NAMEFROM a,bWHERE a.ID(+)=b.ID AND a.ID(+) IS NULL;

先做外连接再过滤

内连接, join key 判断,无结果

内连接 ,“+” 无效

内连接 ,“+” 无效

一般外连接,无过滤

Table a Table b

Page 13: Something about oracle joins

ITPUB2011 技术沙龙上海站

新旧 Join 语法 –理解 SQL86 中的“ +”Conclusion: + operator的确是 outer join语法

– 如果漏掉 righ table 端条件没有写 + ,则语义上是先做outer join, 然后做 filter

– 如果 righ table 端其他列选择具体值或有对应列的 join,但是漏掉 + ,则 Oracle 会将语句转为 inner join

– 如果 righ table 端条件是 IS NULL ,则是先外连接,再做 filter, 当然,如果是 IS NOT NULL ,则也转为内连接

– left table 的单列条件都是 filter

Page 14: Something about oracle joins

ITPUB2011 技术沙龙上海站

新旧 Join 语法 - 理解 SQL92 的 on 和where

ITPUB 问题:在两表查询时, on 和 where 到底没有没区别? YES OR NO ?

Inner Join :SELECT a.ID,a.NAME,b.ID,b.NAMEFROM a,bWHERE a.ID=b.ID AND a.NAME = b.NAME;

SELECT a.ID,a.NAME,b.ID,b.NAMEFROM a INNER JOIN bON a.ID=b.ID AND a.NAME = b.NAME;

Page 15: Something about oracle joins

ITPUB2011 技术沙龙上海站

新旧 Join 语法 - 理解 SQL92 的 on 和where

对内连接来说,条件写在 on 里还是 where 里,

完全没有区别执行计划----------------------------------------------------------Plan hash value: 652036164

---------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |---------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 2 | 20 | 7 (15)| 00:00:01 ||* 1 | HASH JOIN | | 2 | 20 | 7 (15)| 00:00:01 || 2 | TABLE ACCESS FULL| A | 2 | 10 | 3 (0)| 00:00:01 ||* 3 | TABLE ACCESS FULL| B | 3 | 15 | 3 (0)| 00:00:01 |---------------------------------------------------------------------------

Predicate Information (identified by operation id):---------------------------------------------------

1 - access("A"."ID"="B"."ID" AND "A"."NAME"="B"."NAME") 3 - filter("B"."ID" IS NOT NULL)

Page 16: Something about oracle joins

ITPUB2011 技术沙龙上海站

新旧 Join 语法 - 理解 SQL92 的 on 和where

92语法的 on 和 where的区别,主要体现在 Outer Join中SELECT *FROM hr.departments deptRIGHT JOIN hr.locations locON dept.location_id=loc.location_id AND loc.city='Seattle';

Page 17: Something about oracle joins

ITPUB2011 技术沙龙上海站

新旧 Join 语法 - 理解 SQL92 的 on 和where

将前面的语句进行改写:SELECT *FROM hr.departments dept LEFT JOIN hr.locations locON dept.location_id=loc.location_id AND loc.city='Seattle';

Page 18: Something about oracle joins

ITPUB2011 技术沙龙上海站

新旧 Join 语法 - 理解 SQL92 的 on 和whereon 和 where混用的情况 (1)

SELECT *FROM hr.departments dept LEFT JOIN hr.locations locON dept.location_id=loc.location_id AND loc.city='Seattle'WHERE loc.location_id>1500;

Page 19: Something about oracle joins

ITPUB2011 技术沙龙上海站

新旧 Join 语法 - 理解 SQL92 的 on 和where

on 和 where混用的情况 (2)SELECT *FROM hr.departments dept RIGHT JOIN hr.locations locON dept.location_id=loc.location_id AND loc.city='Seattle'WHERE loc.location_id>1500;

Page 20: Something about oracle joins

ITPUB2011 技术沙龙上海站

新旧 Join 语法 - 理解 SQL92 的 on 和where

Conclusion: on is join condition where is filter condition

最终解决问题

寻找合适正确的语法支撑

分析对象的属性及相互关系

明确 SQL 的目标

Page 21: Something about oracle joins

ITPUB2011 技术沙龙上海站

新旧 Join 语法 - 何时用新语法 从前面的内容可以看出

– Oracle 内部还是偏向于老语法

新语法虽好,但是有的版本有 BUG– 主要集中在 Outer Join 中,要做足测试工作– Inner Join 没有必要考虑新语法– 要遵循团队规范

+operator 对复杂 Outer Join 有限制– + 不能与 OR 或 IN 连用、不能与子查询连用– + 要求多表外连接,一个表至多外连接另一个表– 其他可以参考 SQL Reference

Page 22: Something about oracle joins

ITPUB2011 技术沙龙上海站

新旧 Join 语法 - 何时用新语法+operator 的限制:

--ORA-01719 OR 和 IN 都不可以和 + 连用SELECT *FROM test1 a,test2 bWHERE a.ID=b.id(+) OR a.NAME IS NOT NULL;

--OKSELECT *FROM test1 a,test2 bWHERE a.ID=b.id(+) AND a.NAME IS NOT NULL;

--ORA-01799 + 不能与子查询连用SELECT *FROM test1 a,test2 bWHERE a.ID=b.id(+) AND a.NAME(+) IN (SELECT c.NAME FROM test3 c);

--OKSELECT *FROM test1 a,test2 bWHERE a.ID=b.id(+) AND a.NAME IN (SELECT c.NAME FROM test3 c);

Page 23: Something about oracle joins

ITPUB2011 技术沙龙上海站

新旧 Join 语法 -Examples用 +operator改写 ANSI FULL JOIN

SELECT a.ID,b.IDFROM a FULL JOIN bON a.ID=b.ID;

SELECT a.ID,b.IDFROM a,b WHERE a.ID=b.ID(+)UNION ALLSELECT a.ID,b.IDFROM a,b WHERE a.ID(+)=b.ID AND a.ID IS NULL;

分析: FULL JOIN 就是两个 left outer Join+ 去掉一边 left outer Join 中包含的 Inner Join 结果

My dear,这个和ANTI JOIN好像啊

Page 24: Something about oracle joins

ITPUB2011 技术沙龙上海站

常见 Join问题和 Tuning- 关联 update 及优化

典型的错误写法,导致性能问题,事实是错误的 UPDATE

Page 25: Something about oracle joins

ITPUB2011 技术沙龙上海站

常见 Join问题和 Tuning- 关联 update 及优化

关联 update 在 Oracle里不要忘记过滤条件

Page 26: Something about oracle joins

ITPUB2011 技术沙龙上海站

常见 Join问题和 Tuning- 关联 update 及优化

普通写法需要多次访问源表,可以考虑merge

Page 27: Something about oracle joins

ITPUB2011 技术沙龙上海站

常见 Join问题和 Tuning- 关联 update 及优化

如果数据源表的 join key 是 preserved key,则可以使用 update inline view的方法,当然还有其他限制。( BYPASS_UJVC hint)

Page 28: Something about oracle joins

ITPUB2011 技术沙龙上海站

常见 Join问题和 Tuning-Semi Join 和 Anti Join 注意点SELECT * FROM a WHERE a.object_name IN (SELECT b.object_name FROM b);

SELECT * FROM a WHERE EXISTS (SELECT 1 FROM b WHERE a.object_name=b.object_name);

Page 29: Something about oracle joins

ITPUB2011 技术沙龙上海站

常见 Join问题和 Tuning-Semi Join 和 Anti Join 注意点

SELECT * FROM a WHERE a.object_name IN (SELECT b.object_name FROM b)OR a.object_id < (SELECT b.object_id FROM b WHERE b.object_id=80000);

OR 限制

Page 30: Something about oracle joins

ITPUB2011 技术沙龙上海站

常见 Join问题和 Tuning-Semi Join 和 Anti Join 注意点用 union改写,逻辑读从 1594911下降到 1091SELECT * FROM a WHERE a.object_name IN (SELECT b.object_name FROM b)UNIONSELECT * FROM a WHERE a.object_id < (SELECT b.object_id FROM b WHERE b.object_id=80000);

Page 31: Something about oracle joins

ITPUB2011 技术沙龙上海站

常见 Join问题和 Tuning-Semi Join 和 Anti Join 注意点

NOT IN 和 NOT EXISTS要实现等价条件多SELECT * FROM a WHERE a.object_name NOT IN (SELECT b.object_name FROM b);

SELECT * FROM a WHERE NOT EXISTS (SELECT 1 FROM b WHERE a.object_name=b.object_name)

Page 32: Something about oracle joins

ITPUB2011 技术沙龙上海站

常见 Join问题和 Tuning-Semi Join 和 Anti Join 注意点

下面是11g下NOT IN计划

11g之前的计划

Page 33: Something about oracle joins

ITPUB2011 技术沙龙上海站

常见 Join问题和 Tuning-Semi Join 和 Anti Join 注意点--not anti joinSELECT * FROM a WHERE a.object_name NOT IN (SELECT b.object_name FROM b WHERE b.object_name IS NOT NULL);

--anti joinSELECT * FROM a WHERE a.object_name IS NOT NULL AND a.object_name NOT IN (SELECT b.object_name FROM b WHERE b.object_name IS NOT NULL);

Page 34: Something about oracle joins

ITPUB2011 技术沙龙上海站

常见 Join问题和 Tuning-Semi Join 和 Anti Join 注意点

Anti Join 同样注意 OR 的问题

Page 35: Something about oracle joins

ITPUB2011 技术沙龙上海站

常见 Join问题和 Tuning-Semi Join 和 Anti Join 注意点

用 union改写含有 or 的 anti join,filter变为 anti join 和 union…逻辑读减少,虽然 filter的逻辑读也不大

Page 36: Something about oracle joins

ITPUB2011 技术沙龙上海站

常见 Join问题和 Tuning-Set操作转换Minus 一定条件下的改写: anti join 、外连接SELECT a.object_id,a.object_name FROM aMINUSSELECT b.object_id,b.object_name FROM b;

SELECT a.object_id,a.object_name FROM aWHERE NOT EXISTS (SELECT 1 FROM b WHERE a.object_id=b.object_id AND a.object_name=b.object_name);

Page 37: Something about oracle joins

ITPUB2011 技术沙龙上海站

常见 Join问题和 Tuning-Set操作转换 Intersect一定条件下的改写: inner

join 、 semi joinSELECT a.object_id,a.object_name FROM aINTERSECTSELECT b.object_id,b.object_name FROM b;

SELECT a.object_id,a.object_name FROM aWHERE EXISTS (SELECT 1 FROM b WHERE a.object_id=b.object_id AND a.object_name=b.object_name);

Page 38: Something about oracle joins

ITPUB2011 技术沙龙上海站