SlideShare ist ein Scribd-Unternehmen logo
1 von 38
Something about Oracle Joins 丁俊  dingjun123 mailto:dingjunlove@163.com
内容简介 ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
内容简介续 ,[object Object],[object Object],[object Object],[object Object]
Oracle Join 简介 -Join 的重要性 ,[object Object],[object Object],[object Object],[object Object],[object Object]
Oracle Join 简介 -Join 的类别 ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
Oracle Join 简介 -Examples ,[object Object],SELECT a.ename,b.ename, a.hiredate,b.hiredate FROM scott.emp a,scott.emp b WHERE a.hiredate <= b.hiredate AND  a.empno <> b.empno; …… 使用 Non-equi-join 要考虑清楚
Oracle Join 简介 -Examples ,[object Object],SELECT a.ename,a.hiredate FROM scott.emp a WHERE  EXISTS (SELECT 1 FROM scott.emp b WHERE a.hiredate <= b.hiredate AND  a.empno <> b.empno); Semi join  短路 Q : Semi join 最常见经典应用? A :找结果集是否存在数据
Oracle Join 简介 -Examples ,[object Object],SELECT a.ename,a.hiredate FROM scott.emp a WHERE  NOT EXISTS (SELECT 1 FROM scott.emp b WHERE a.hiredate <= b.hiredate AND  a.empno <> b.empno); Anti join  无短路 No matched results,so returned
新旧 Join 语法 –理解 SQL86 中的“ +” ,[object Object],Table a Table b right join SELECT a.ID,a.NAME,a.code, b.ID,b.NAME,b.code FROM a,b WHERE a.ID(+)=b.ID AND a.NAME(+)=b.NAME AND TO_NUMBER(a.code)=b.code; 注意复杂外连接的写法,不要丢掉 + 号
新旧 Join 语法 –理解 SQL86 中的“ +” ,[object Object],SELECT a.ID,a.NAME,a.code, b.ID,b.NAME,b.code FROM a,b WHERE a.ID(+)=b.ID AND a.NAME(+)=b.NAME AND TO_NUMBER(a.code(+))=b.code; My god!so esay! My god!so easy!
新旧 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 only the rows resulting from a simple join , but without a warning or error to advise you that you do not have the results of an outer join. 理解文档中的 Join conditions 的含义很重要,文档并不详细。 可能会导致理解错误: 只要 right table 的列漏掉 + 就不是 外连接?
新旧 Join 语法 –理解 SQL86 中的“ +” Table a Table b SELECT a.ID,a.NAME,b.ID,b.NAME FROM a,b WHERE a.ID(+)=b.ID AND a.ID IS NULL;  SELECT a.ID,a.NAME,b.ID,b.NAME  FROM a,b WHERE a.ID=b.ID AND a.ID IS NULL;  SELECT a.ID,a.NAME,b.ID,b.NAME FROM a,b WHERE a.ID(+)=b.ID AND a.NAME=‘b’;  SELECT a.ID,a.NAME,b.ID,b.NAME FROM a,b WHERE a.ID(+)=b.ID AND a.NAME=b.NAME;  SELECT a.ID,a.NAME,b.ID,b.NAME FROM a,b WHERE a.ID(+)=b.ID AND a.ID(+) IS NULL;  先做外连接再过滤 内连接, join key 判断,无结果 内连接 ,“+” 无效 内连接 ,“+” 无效 一般外连接,无过滤 Table a Table b
新旧 Join 语法 –理解 SQL86 中的“ +” ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
新旧 Join 语法 - 理解 SQL92 的 on 和 where ,[object Object],[object Object],Inner Join : SELECT a.ID,a.NAME,b.ID,b.NAME FROM a,b WHERE a.ID=b.ID AND a.NAME = b.NAME; SELECT a.ID,a.NAME,b.ID,b.NAME FROM a INNER JOIN b ON a.ID=b.ID AND a.NAME = b.NAME;
新旧 Join 语法 - 理解 SQL92 的 on 和 where ,[object Object],[object Object],执行计划 ---------------------------------------------------------- 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(&quot;A&quot;.&quot;ID&quot;=&quot;B&quot;.&quot;ID&quot; AND &quot;A&quot;.&quot;NAME&quot;=&quot;B&quot;.&quot;NAME&quot;) 3 - filter(&quot;B&quot;.&quot;ID&quot; IS NOT NULL)
新旧 Join 语法 - 理解 SQL92 的 on 和 where ,[object Object],SELECT * FROM hr.departments dept RIGHT JOIN  hr.locations loc ON dept.location_id=loc.location_id AND loc.city='Seattle';
新旧 Join 语法 - 理解 SQL92 的 on 和 where ,[object Object],SELECT * FROM hr.departments dept  LEFT JOIN  hr.locations loc ON dept.location_id=loc.location_id AND loc.city='Seattle';
新旧 Join 语法 - 理解 SQL92 的 on 和 where ,[object Object],SELECT * FROM hr.departments dept  LEFT JOIN  hr.locations loc ON dept.location_id=loc.location_id AND loc.city='Seattle' WHERE loc.location_id>1500 ;
新旧 Join 语法 - 理解 SQL92 的 on 和 where ,[object Object],SELECT * FROM hr.departments dept  RIGHT JOIN  hr.locations loc ON dept.location_id=loc.location_id AND loc.city='Seattle' WHERE loc.location_id>1500 ;
新旧 Join 语法 - 理解 SQL92 的 on 和 where ,[object Object],[object Object],[object Object],最终解决问题  寻找合适正确的语法支撑  分析对象的属性及相互关系  明确 SQL 的目标
新旧 Join 语法 - 何时用新语法 ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
新旧 Join 语法 - 何时用新语法 ,[object Object],--ORA-01719 OR 和 IN 都不可以和 + 连用 SELECT * FROM test1 a,test2 b WHERE a.ID=b.id(+)  OR  a.NAME IS NOT NULL; --OK SELECT * FROM test1 a,test2 b WHERE a.ID=b.id(+) AND a.NAME IS NOT NULL; --ORA-01799 + 不能与子查询连用 SELECT * FROM test1 a,test2 b WHERE a.ID=b.id(+)  AND  a.NAME(+) IN (SELECT c.NAME FROM test3 c) ; --OK SELECT * FROM test1 a,test2 b WHERE a.ID=b.id(+)  AND a.NAME IN (SELECT c.NAME FROM test3 c);
新旧 Join 语法 -Examples 用 +operator 改写 ANSI FULL JOIN SELECT a.ID,b.ID FROM a FULL JOIN b ON a.ID=b.ID; SELECT a.ID,b.ID FROM a,b WHERE a.ID=b.ID(+) UNION ALL SELECT a.ID,b.ID FROM 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 好像啊
常见 Join 问题和 Tuning- 关联 update 及优化 ,[object Object]
常见 Join 问题和 Tuning- 关联 update 及优化 ,[object Object]
常见 Join 问题和 Tuning- 关联 update 及优化 ,[object Object]
常见 Join 问题和 Tuning- 关联 update 及优化 ,[object Object]
常见 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);
常见 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 限制
常见 Join 问题和 Tuning- Semi Join 和 Anti Join 注意点 ,[object Object],SELECT * FROM a  WHERE a.object_name IN  (SELECT b.object_name FROM b) UNION SELECT * FROM a WHERE a.object_id < (SELECT b.object_id FROM b WHERE b.object_id=80000);
常见 Join 问题和 Tuning- Semi Join 和 Anti Join 注意点 ,[object Object],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)
常见 Join 问题和 Tuning- Semi Join 和 Anti Join 注意点 ,[object Object],11g 之前的计划
常见 Join 问题和 Tuning- Semi Join 和 Anti Join 注意点 --not anti join SELECT * FROM a  WHERE a.object_name NOT IN  (SELECT b.object_name FROM b WHERE b.object_name IS NOT NULL); --anti join SELECT * 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 );
常见 Join 问题和 Tuning- Semi Join 和 Anti Join 注意点 ,[object Object]
常见 Join 问题和 Tuning- Semi Join 和 Anti Join 注意点 ,[object Object]
常见 Join 问题和 Tuning-Set 操作转换 ,[object Object],SELECT a.object_id,a.object_name FROM a MINUS SELECT b.object_id,b.object_name FROM b; SELECT a.object_id,a.object_name FROM a WHERE NOT EXISTS ( SELECT 1 FROM b  WHERE a.object_id=b.object_id  AND a.object_name=b.object_name);
常见 Join 问题和 Tuning-Set 操作转换 ,[object Object],SELECT a.object_id,a.object_name FROM a INTERSECT SELECT b.object_id,b.object_name FROM b; SELECT a.object_id,a.object_name FROM a WHERE EXISTS ( SELECT 1 FROM b  WHERE a.object_id=b.object_id  AND a.object_name=b.object_name);
 

Weitere ähnliche Inhalte

Andere mochten auch

Andere mochten auch (7)

Hash join
Hash joinHash join
Hash join
 
Corba and-java
Corba and-javaCorba and-java
Corba and-java
 
Join operation
Join operationJoin operation
Join operation
 
Rmi, corba and java beans
Rmi, corba and java beansRmi, corba and java beans
Rmi, corba and java beans
 
Oracle: Joins
Oracle: JoinsOracle: Joins
Oracle: Joins
 
Webinar Smile et WSO2
Webinar Smile et WSO2Webinar Smile et WSO2
Webinar Smile et WSO2
 
Ejb
Ejb Ejb
Ejb
 

Ähnlich wie Something about oracle joins

Sql语句的优化
Sql语句的优化Sql语句的优化
Sql语句的优化abszhanghe
 
Sql Server 高级技巧系列之三整体优化
Sql Server 高级技巧系列之三整体优化Sql Server 高级技巧系列之三整体优化
Sql Server 高级技巧系列之三整体优化向 翔
 
Mysql fast share
Mysql fast shareMysql fast share
Mysql fast sharerfyiamcool
 
A.oracle 数据字典与脚本初步
A.oracle 数据字典与脚本初步A.oracle 数据字典与脚本初步
A.oracle 数据字典与脚本初步WASecurity
 
数据库性能诊断的七种武器
数据库性能诊断的七种武器数据库性能诊断的七种武器
数据库性能诊断的七种武器Leyi (Kamus) Zhang
 
Web3.0 与人工智能
Web3.0 与人工智能Web3.0 与人工智能
Web3.0 与人工智能Raullen Chai
 
1 C入門教學
1  C入門教學1  C入門教學
1 C入門教學Sita Liu
 
第6章 数据查询
第6章 数据查询第6章 数据查询
第6章 数据查询hanmo1988
 
C++工程实践
C++工程实践C++工程实践
C++工程实践Shuo Chen
 
ajax_onlinemad
ajax_onlinemadajax_onlinemad
ajax_onlinemadKitor23
 
搜狐Pv insight(py)技术交流
搜狐Pv insight(py)技术交流搜狐Pv insight(py)技术交流
搜狐Pv insight(py)技术交流bj
 
搜狐Pv insight(py)技术交流
搜狐Pv insight(py)技术交流搜狐Pv insight(py)技术交流
搜狐Pv insight(py)技术交流jondynet
 
Mysql introduction-and-performance-optimization
Mysql introduction-and-performance-optimizationMysql introduction-and-performance-optimization
Mysql introduction-and-performance-optimizationisnull
 
数据库原理第三章
数据库原理第三章数据库原理第三章
数据库原理第三章strun
 
Huangjing renren
Huangjing renrenHuangjing renren
Huangjing renrend0nn9n
 
Ria的强力后盾:rest+海量存储
Ria的强力后盾:rest+海量存储 Ria的强力后盾:rest+海量存储
Ria的强力后盾:rest+海量存储 zhen chen
 
Sql培训 (1)
Sql培训 (1)Sql培训 (1)
Sql培训 (1)jhao niu
 
Linux c++ 编程之链接与装载 -基础篇--v0.3--20120509
Linux c++ 编程之链接与装载 -基础篇--v0.3--20120509Linux c++ 编程之链接与装载 -基础篇--v0.3--20120509
Linux c++ 编程之链接与装载 -基础篇--v0.3--20120509tidesq
 
组件交互模式的非主流研究
组件交互模式的非主流研究组件交互模式的非主流研究
组件交互模式的非主流研究youalab
 

Ähnlich wie Something about oracle joins (20)

Sql语句的优化
Sql语句的优化Sql语句的优化
Sql语句的优化
 
Sql Server 高级技巧系列之三整体优化
Sql Server 高级技巧系列之三整体优化Sql Server 高级技巧系列之三整体优化
Sql Server 高级技巧系列之三整体优化
 
Mysql fast share
Mysql fast shareMysql fast share
Mysql fast share
 
A.oracle 数据字典与脚本初步
A.oracle 数据字典与脚本初步A.oracle 数据字典与脚本初步
A.oracle 数据字典与脚本初步
 
数据库性能诊断的七种武器
数据库性能诊断的七种武器数据库性能诊断的七种武器
数据库性能诊断的七种武器
 
Web3.0 与人工智能
Web3.0 与人工智能Web3.0 与人工智能
Web3.0 与人工智能
 
1 C入門教學
1  C入門教學1  C入門教學
1 C入門教學
 
第6章 数据查询
第6章 数据查询第6章 数据查询
第6章 数据查询
 
C++工程实践
C++工程实践C++工程实践
C++工程实践
 
ajax_onlinemad
ajax_onlinemadajax_onlinemad
ajax_onlinemad
 
搜狐Pv insight(py)技术交流
搜狐Pv insight(py)技术交流搜狐Pv insight(py)技术交流
搜狐Pv insight(py)技术交流
 
搜狐Pv insight(py)技术交流
搜狐Pv insight(py)技术交流搜狐Pv insight(py)技术交流
搜狐Pv insight(py)技术交流
 
Mysql introduction-and-performance-optimization
Mysql introduction-and-performance-optimizationMysql introduction-and-performance-optimization
Mysql introduction-and-performance-optimization
 
数据库原理第三章
数据库原理第三章数据库原理第三章
数据库原理第三章
 
Huangjing renren
Huangjing renrenHuangjing renren
Huangjing renren
 
Ria的强力后盾:rest+海量存储
Ria的强力后盾:rest+海量存储 Ria的强力后盾:rest+海量存储
Ria的强力后盾:rest+海量存储
 
Sql培训 (1)
Sql培训 (1)Sql培训 (1)
Sql培训 (1)
 
Linux c++ 编程之链接与装载 -基础篇--v0.3--20120509
Linux c++ 编程之链接与装载 -基础篇--v0.3--20120509Linux c++ 编程之链接与装载 -基础篇--v0.3--20120509
Linux c++ 编程之链接与装载 -基础篇--v0.3--20120509
 
组件交互模式的非主流研究
组件交互模式的非主流研究组件交互模式的非主流研究
组件交互模式的非主流研究
 
Optimzing mysql
Optimzing mysqlOptimzing mysql
Optimzing mysql
 

Mehr von mysqlops

The simplethebeautiful
The simplethebeautifulThe simplethebeautiful
The simplethebeautifulmysqlops
 
Oracle数据库分析函数详解
Oracle数据库分析函数详解Oracle数据库分析函数详解
Oracle数据库分析函数详解mysqlops
 
Percona Live 2012PPT:mysql-security-privileges-and-user-management
Percona Live 2012PPT:mysql-security-privileges-and-user-managementPercona Live 2012PPT:mysql-security-privileges-and-user-management
Percona Live 2012PPT:mysql-security-privileges-and-user-managementmysqlops
 
Percona Live 2012PPT: introduction-to-mysql-replication
Percona Live 2012PPT: introduction-to-mysql-replicationPercona Live 2012PPT: introduction-to-mysql-replication
Percona Live 2012PPT: introduction-to-mysql-replicationmysqlops
 
Percona Live 2012PPT: MySQL Cluster And NDB Cluster
Percona Live 2012PPT: MySQL Cluster And NDB ClusterPercona Live 2012PPT: MySQL Cluster And NDB Cluster
Percona Live 2012PPT: MySQL Cluster And NDB Clustermysqlops
 
Percona Live 2012PPT: MySQL Query optimization
Percona Live 2012PPT: MySQL Query optimizationPercona Live 2012PPT: MySQL Query optimization
Percona Live 2012PPT: MySQL Query optimizationmysqlops
 
Pldc2012 innodb architecture and internals
Pldc2012 innodb architecture and internalsPldc2012 innodb architecture and internals
Pldc2012 innodb architecture and internalsmysqlops
 
DBA新人的述职报告
DBA新人的述职报告DBA新人的述职报告
DBA新人的述职报告mysqlops
 
分布式爬虫
分布式爬虫分布式爬虫
分布式爬虫mysqlops
 
MySQL应用优化实践
MySQL应用优化实践MySQL应用优化实践
MySQL应用优化实践mysqlops
 
eBay EDW元数据管理及应用
eBay EDW元数据管理及应用eBay EDW元数据管理及应用
eBay EDW元数据管理及应用mysqlops
 
基于协程的网络开发框架的设计与实现
基于协程的网络开发框架的设计与实现基于协程的网络开发框架的设计与实现
基于协程的网络开发框架的设计与实现mysqlops
 
eBay基于Hadoop平台的用户邮件数据分析
eBay基于Hadoop平台的用户邮件数据分析eBay基于Hadoop平台的用户邮件数据分析
eBay基于Hadoop平台的用户邮件数据分析mysqlops
 
对MySQL DBA的一些思考
对MySQL DBA的一些思考对MySQL DBA的一些思考
对MySQL DBA的一些思考mysqlops
 
QQ聊天系统后台架构的演化与启示
QQ聊天系统后台架构的演化与启示QQ聊天系统后台架构的演化与启示
QQ聊天系统后台架构的演化与启示mysqlops
 
腾讯即时聊天IM1.4亿在线背后的故事
腾讯即时聊天IM1.4亿在线背后的故事腾讯即时聊天IM1.4亿在线背后的故事
腾讯即时聊天IM1.4亿在线背后的故事mysqlops
 
分布式存储与TDDL
分布式存储与TDDL分布式存储与TDDL
分布式存储与TDDLmysqlops
 
MySQL数据库生产环境维护
MySQL数据库生产环境维护MySQL数据库生产环境维护
MySQL数据库生产环境维护mysqlops
 

Mehr von mysqlops (20)

The simplethebeautiful
The simplethebeautifulThe simplethebeautiful
The simplethebeautiful
 
Oracle数据库分析函数详解
Oracle数据库分析函数详解Oracle数据库分析函数详解
Oracle数据库分析函数详解
 
Percona Live 2012PPT:mysql-security-privileges-and-user-management
Percona Live 2012PPT:mysql-security-privileges-and-user-managementPercona Live 2012PPT:mysql-security-privileges-and-user-management
Percona Live 2012PPT:mysql-security-privileges-and-user-management
 
Percona Live 2012PPT: introduction-to-mysql-replication
Percona Live 2012PPT: introduction-to-mysql-replicationPercona Live 2012PPT: introduction-to-mysql-replication
Percona Live 2012PPT: introduction-to-mysql-replication
 
Percona Live 2012PPT: MySQL Cluster And NDB Cluster
Percona Live 2012PPT: MySQL Cluster And NDB ClusterPercona Live 2012PPT: MySQL Cluster And NDB Cluster
Percona Live 2012PPT: MySQL Cluster And NDB Cluster
 
Percona Live 2012PPT: MySQL Query optimization
Percona Live 2012PPT: MySQL Query optimizationPercona Live 2012PPT: MySQL Query optimization
Percona Live 2012PPT: MySQL Query optimization
 
Pldc2012 innodb architecture and internals
Pldc2012 innodb architecture and internalsPldc2012 innodb architecture and internals
Pldc2012 innodb architecture and internals
 
DBA新人的述职报告
DBA新人的述职报告DBA新人的述职报告
DBA新人的述职报告
 
分布式爬虫
分布式爬虫分布式爬虫
分布式爬虫
 
MySQL应用优化实践
MySQL应用优化实践MySQL应用优化实践
MySQL应用优化实践
 
eBay EDW元数据管理及应用
eBay EDW元数据管理及应用eBay EDW元数据管理及应用
eBay EDW元数据管理及应用
 
基于协程的网络开发框架的设计与实现
基于协程的网络开发框架的设计与实现基于协程的网络开发框架的设计与实现
基于协程的网络开发框架的设计与实现
 
eBay基于Hadoop平台的用户邮件数据分析
eBay基于Hadoop平台的用户邮件数据分析eBay基于Hadoop平台的用户邮件数据分析
eBay基于Hadoop平台的用户邮件数据分析
 
对MySQL DBA的一些思考
对MySQL DBA的一些思考对MySQL DBA的一些思考
对MySQL DBA的一些思考
 
QQ聊天系统后台架构的演化与启示
QQ聊天系统后台架构的演化与启示QQ聊天系统后台架构的演化与启示
QQ聊天系统后台架构的演化与启示
 
腾讯即时聊天IM1.4亿在线背后的故事
腾讯即时聊天IM1.4亿在线背后的故事腾讯即时聊天IM1.4亿在线背后的故事
腾讯即时聊天IM1.4亿在线背后的故事
 
分布式存储与TDDL
分布式存储与TDDL分布式存储与TDDL
分布式存储与TDDL
 
MySQL数据库生产环境维护
MySQL数据库生产环境维护MySQL数据库生产环境维护
MySQL数据库生产环境维护
 
Memcached
MemcachedMemcached
Memcached
 
DevOPS
DevOPSDevOPS
DevOPS
 

Something about oracle joins

  • 1. Something about Oracle Joins 丁俊 dingjun123 mailto:dingjunlove@163.com
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11. 新旧 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 only the rows resulting from a simple join , but without a warning or error to advise you that you do not have the results of an outer join. 理解文档中的 Join conditions 的含义很重要,文档并不详细。 可能会导致理解错误: 只要 right table 的列漏掉 + 就不是 外连接?
  • 12. 新旧 Join 语法 –理解 SQL86 中的“ +” Table a Table b SELECT a.ID,a.NAME,b.ID,b.NAME FROM a,b WHERE a.ID(+)=b.ID AND a.ID IS NULL; SELECT a.ID,a.NAME,b.ID,b.NAME FROM a,b WHERE a.ID=b.ID AND a.ID IS NULL; SELECT a.ID,a.NAME,b.ID,b.NAME FROM a,b WHERE a.ID(+)=b.ID AND a.NAME=‘b’; SELECT a.ID,a.NAME,b.ID,b.NAME FROM a,b WHERE a.ID(+)=b.ID AND a.NAME=b.NAME; SELECT a.ID,a.NAME,b.ID,b.NAME FROM a,b WHERE a.ID(+)=b.ID AND a.ID(+) IS NULL; 先做外连接再过滤 内连接, join key 判断,无结果 内连接 ,“+” 无效 内连接 ,“+” 无效 一般外连接,无过滤 Table a Table b
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23. 新旧 Join 语法 -Examples 用 +operator 改写 ANSI FULL JOIN SELECT a.ID,b.ID FROM a FULL JOIN b ON a.ID=b.ID; SELECT a.ID,b.ID FROM a,b WHERE a.ID=b.ID(+) UNION ALL SELECT a.ID,b.ID FROM 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 好像啊
  • 24.
  • 25.
  • 26.
  • 27.
  • 28. 常见 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);
  • 29. 常见 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 限制
  • 30.
  • 31.
  • 32.
  • 33. 常见 Join 问题和 Tuning- Semi Join 和 Anti Join 注意点 --not anti join SELECT * FROM a WHERE a.object_name NOT IN (SELECT b.object_name FROM b WHERE b.object_name IS NOT NULL); --anti join SELECT * 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 );
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.  

Hinweis der Redaktion

  1. Semi join 有短路功能 :意思是不全找,找到就 OK ,只要对应每行,查找到匹配的记录,则返回,然后继续下一次查找 Semi join 的一个实际使用,找结果集是否存在数据: select count(*) from dual where exists (select 1 from …); Semi join 也可以使用三大 join 算法, OK ,有 nested loops semi,hash joins semi and merge joins semin……. 以及对应的 hint 控制
  2. Anti Join 无短路 ,必须对应每行,与对子查询表全部查询一遍,然后无匹配,则返回此行记录,有匹配不返回 和 Semi join 一样,它也有三大算法以及对应的 hint 控制
  3. -- 检查执行计划,未发现 outer, 检查谓词未发现 + -- 语法级 SQL 转换 DROP TABLE a ; DROP TABLE b ; CREATE TABLE a (ID NUMBER,NAME VARCHAR2( 10 ), code VARCHAR2( 10 )); INSERT INTO a VALUES( 1 ,&apos;a&apos;,&apos;00001&apos;); INSERT INTO a VALUES( 2 ,&apos;b&apos;,&apos;00002&apos;); CREATE TABLE b (ID NUMBER,NAME VARCHAR2( 10 ), code NUMBER( 10 )); INSERT INTO b SELECT * FROM a ; INSERT INTO b VALUES( 3 ,&apos;c&apos;, 3 ); COMMIT; SELECT * FROM a ; SELECT * FROM b ; dingjun123@ORADB&gt; SELECT a.ID,a.NAME,a.code, 2 b.ID,b.NAME,b.code 3 FROM a,b 4 WHERE a.ID(+)=b.ID AND a.NAME(+)=b.NAME 5 AND TO_NUMBER(a.code)=b.code; 已选择 2 行。 已用时间 : 00: 00: 00.01 执行计划 ---------------------------------------------------------- Plan hash value: 652036164 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 60 | 7 (15)| 00:00:01 | |* 1 | HASH JOIN | | 1 | 60 | 7 (15)| 00:00:01 | | 2 | TABLE ACCESS FULL| A | 2 | 54 | 3 (0)| 00:00:01 | | 3 | TABLE ACCESS FULL| B | 3 | 99 | 3 (0)| 00:00:01 | --------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - access(&amp;quot;A&amp;quot;.&amp;quot;ID&amp;quot;=&amp;quot;B&amp;quot;.&amp;quot;ID&amp;quot; AND &amp;quot;A&amp;quot;.&amp;quot;NAME&amp;quot;=&amp;quot;B&amp;quot;.&amp;quot;NAME&amp;quot; AND &amp;quot;B&amp;quot;.&amp;quot;CODE&amp;quot;=TO_NUMBER(&amp;quot;A&amp;quot;.&amp;quot;CODE&amp;quot;)) Note ----- - dynamic sampling used for this statement (level=2) 统计信息 ---------------------------------------------------------- 7 recursive calls 0 db block gets 31 consistent gets 0 physical reads 0 redo size 775 bytes sent via SQL*Net to client 416 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 2 rows processed dingjun123@ORADB&gt; SELECT a.ID,a.NAME,a.code, 2 b.ID,b.NAME,b.code 3 FROM a,b 4 WHERE a.ID(+)=b.ID AND a.NAME(+)=b.NAME 5 AND TO_NUMBER(a.code(+))=b.code; 已选择 3 行。 已用时间 : 00: 00: 00.01 执行计划 ---------------------------------------------------------- Plan hash value: 843196925 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 3 | 180 | 7 (15)| 00:00:01 | |* 1 | HASH JOIN OUTER | | 3 | 180 | 7 (15)| 00:00:01 | | 2 | TABLE ACCESS FULL| B | 3 | 99 | 3 (0)| 00:00:01 | | 3 | TABLE ACCESS FULL| A | 2 | 54 | 3 (0)| 00:00:01 | --------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - access(&amp;quot;A&amp;quot;.&amp;quot;ID&amp;quot;(+)=&amp;quot;B&amp;quot;.&amp;quot;ID&amp;quot; AND &amp;quot;A&amp;quot;.&amp;quot;NAME&amp;quot;(+)=&amp;quot;B&amp;quot;.&amp;quot;NAME&amp;quot; AND &amp;quot;B&amp;quot;.&amp;quot;CODE&amp;quot;=TO_NUMBER(&amp;quot;A&amp;quot;.&amp;quot;CODE&amp;quot;(+)))
  4. -- 理解 +, 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 INSERT INTO a VALUES(NULL,&apos;c&apos;, 3 ); SELECT * FROM a ; SELECT * FROM b ; --1. 是先进行 id 的外连接,然后按 a.id is null 过滤,类似于 anti join ,找没有匹配到的 b 表记录 SELECT a .ID, a .NAME, b .ID, b .NAME FROM a , b WHERE a .ID(+)= b .ID AND a .ID IS NULL; ALTER TABLE a DROP CONSTRAINTS uk_a ; ALTER TABLE b DROP CONSTRAINTS uk_b ; ALTER TABLE b MODIFY ID NULL; SELECT a .ID FROM a , b WHERE a .ID(+)= b .ID AND a .ID IS NULL; SELECT a .ID, a .NAME FROM a WHERE NOT EXISTS (SELECT 1 FROM b WHERE a .ID= b .ID); -- 肯定不返回行,因为是内连接,而且是连接键 IS NULL SELECT a .ID, a .NAME, b .ID, b .NAME FROM a , b WHERE a .ID= b .ID AND a .ID IS NULL; -- 一般内连接, + 无效 SELECT a .ID, a .NAME, b .ID, b .NAME FROM a , b WHERE a .ID(+)= b .ID AND a .NAME=&apos;b&apos;; -- 一般内连接, + 无效 SELECT a .ID, a .NAME, b .ID, b .NAME FROM a , b WHERE a .ID(+)= b .ID AND a .NAME= b .NAME; -- 外连接 SELECT a .ID, a .NAME, b .ID, b .NAME FROM a , b WHERE a .ID(+)= b .ID AND a .ID(+) IS NULL; --DELETE FROM a WHERE ID=3; -- 列换为 name INSERT INTO a VALUES( 3 ,NULL, 3 ); INSERT INTO b VALUES( 4 ,&apos;d&apos;, 4 ); SELECT a .ID, a .NAME, b .ID, b .NAME FROM a , b WHERE a .ID(+)= b .ID AND a .NAME(+) IS NULL; -- 过滤 SELECT a .ID, a .NAME, b .ID, b .NAME FROM a RIGHT JOIN b ON a .ID= b .ID WHERE a .NAME IS NOT NULL; -- 非连接键值 , 下面两个也不同,第 1 个是先外连接后过滤 SELECT a .ID, a .NAME, b .ID, b .NAME FROM a , b WHERE a .ID(+)= b .ID AND a .NAME IS NULL; SELECT a .ID, a .NAME, b .ID, b .NAME FROM a RIGHT JOIN b ON a .ID= b .ID WHERE a .NAME IS NULL; -- 第 2 个内连接 SELECT a .ID, a .NAME, b .ID, b .NAME FROM a , b WHERE a .ID= b .ID AND a .NAME IS NULL; SELECT a .ID, a .NAME, b .ID, b .NAME FROM a , b WHERE a .ID(+)= b .ID AND a .ID IS NOT NULL; SELECT a .ID, a .NAME, b .ID, b .NAME FROM a , b WHERE a .ID(+)= b .ID AND a .NAME IS NOT NULL; --b.id&gt;1 是过滤,先过滤再连接 SELECT a .ID, a .NAME, b .ID, b .NAME FROM a , b WHERE a .ID(+)= b .ID AND b .ID&gt; 1 ;
  5. 老语法改写:只能是 where 条件 1.Where dept.location_id(+)=loc.location_id AND loc.city=‘Seattle’; -- 错误,因为有过滤 2. SELECT * FROM hr . departments dept , hr . locations loc WHERE dept . location_id (+)= loc . location_id AND loc . city =CASE WHEN ( dept . location_id (+) IS NOT NULL) THEN &apos;Seattle&apos; ELSE &apos;Seattle&apos; END; Loc.city= ‘Seattle’ 的前提是前面的 location_id 条件必须匹配或不匹配,这样外连接的条件就完整了 3. 也可以这样改写 SELECT * FROM hr . departments dept , hr . locations loc WHERE loc . location_id = decode ( loc . city ,&apos;Seattle&apos;, dept . location_id (+));
  6. SELECT * FROM hr . departments dept LEFT JOIN hr . locations loc ON dept . location_id = loc . location_id AND loc . city =&apos;Seattle&apos;; SELECT * FROM hr . departments dept LEFT JOIN hr . locations loc ON dept . location_id = loc . location_id AND loc . city (+)=&apos;Seattle&apos;;
  7. 从前面 + 语法分析也可以知道,因为是对非主表过滤,所以语义上是内连接 实际计划也转为内连接,并且 Oracle 很聪明,使用了谓词传递
  8. 因为对主表过滤,所以是先过滤,后外连接 并且也有主表的谓词传递到了从表的谓词
  9. SQL 的分析步骤很重要 不进行详细分析,写不好 SQL ,甚至错误 不清楚对象的属性,约束,索引等信息,不清楚对象间的关系,写的 SQL 可能不高效 不能寻找合适正确的语法支撑,写不好 SQL 分析重于一切,必须先分析,才开始动手构造 SQL
  10. drop TABLE test1 ; drop TABLE test2 ; drop TABLE test3 ; CREATE TABLE test1 AS SELECT 1 id, &apos;aa&apos; NAME FROM dual UNION ALL SELECT 2 , &apos;bb&apos; FROM dual UNION ALL SELECT 3 , &apos;cc&apos; FROM dual ; CREATE TABLE test2 AS SELECT 1 id, &apos;aa&apos; NAME FROM dual UNION ALL SELECT 4 , &apos;dd&apos; FROM dual ; CREATE TABLE test3 AS SELECT 2 id, &apos;bb&apos; NAME FROM dual UNION ALL SELECT 5 , &apos;ee&apos; FROM dual ; SELECT * FROM test1 a , test2 b WHERE a .ID= b .id(+) OR a .NAME IS NOT NULL; SELECT * FROM test1 a , test2 b WHERE a .ID= b .id(+) AND a .NAME IS NOT NULL; SELECT * FROM test1 a , test2 b WHERE a .ID= b .id(+) AND a .NAME(+) IN (SELECT c .NAME FROM test3 c ); SELECT * FROM test1 a , test2 b WHERE a .ID= b .id(+) AND a .NAME IN (SELECT c .NAME FROM test3 c ); SELECT * FROM test1 a , test2 b , test3 c WHERE a .id = b .id(+) AND a .id = c .id(+); DROP TABLE test1 ; DROP TABLE test2 ; DROP TABLE test3 ; CREATE TABLE test1 AS SELECT 1 id, &apos;aa&apos; NAME FROM dual UNION ALL SELECT 2 , &apos;bb&apos; FROM dual ; CREATE TABLE test2 AS SELECT 1 id, &apos;aa&apos; NAME FROM dual UNION ALL SELECT 4 , &apos;dd&apos; FROM dual ; CREATE TABLE test3 AS SELECT 2 id, &apos;bb&apos; NAME FROM dual UNION ALL SELECT 1 , &apos;aa&apos; FROM dual UNION ALL SELECT 4 , &apos;dd&apos; FROM dual UNION ALL SELECT 5 , &apos;ee&apos; FROM dual ; --0ra-01417 一个表最多能外连接到一个表 -- 不知道谁才是基表 SELECT * FROM test1 a , test2 b , test3 c WHERE a .id(+) = b .id AND a .id(+) = c .id; -- 用中间结果集改写 SELECT * FROM (SELECT a .id aid , a .NAME aname , b .id bid , b .NAME bname FROM test1 a , test2 b WHERE a .id(+) = b .id) c , test3 d WHERE c . aid (+) = d .id; -- 基表最终是 test3 SELECT * FROM test1 a RIGHT JOIN test2 b ON a .ID = b .ID RIGHT JOIN test3 c ON a .ID = c .ID; -- 基表最终是 test2 SELECT * FROM test1 a RIGHT JOIN test3 b ON a .ID = b .ID RIGHT JOIN test2 c ON a .ID = c .ID;
  11. a.ID IS NULL 不能写成 a.ID(+) IS NULL, 习惯选择一个连接键判断,其他的也可以,比如 rowid DROP TABLE a ; DROP TABLE b ; CREATE TABLE a (ID NUMBER,NAME VARCHAR2( 10 )); CREATE TABLE b (ID NUMBER,NAME VARCHAR2( 10 )); INSERT INTO a VALUES( 1 ,&apos;a&apos;); INSERT INTO a VALUES( 2 ,&apos;b&apos;); INSERT INTO a VALUES( 3 ,&apos;c&apos;); INSERT INTO b VALUES( 1 ,&apos;a&apos;); INSERT INTO b VALUES( 2 ,&apos;b&apos;); INSERT INTO b VALUES( 4 ,&apos;d&apos;); COMMIT ; SELECT * FROM a ; SELECT * FROM b ; SELECT a .ID, b .ID FROM a FULL JOIN b ON a .ID= b .ID; -- 如果连接条件 1:1, 可以用 union SELECT a .ID, b .ID FROM a , b WHERE a .ID= b .ID(+) UNION SELECT a .ID, b .ID FROM a , b WHERE a .ID(+)= b .ID; -- 非 1:1 应该用 UNION ALL 并且第 2 个语句在 + 号处的列只选出 NULL 看到有些人经常问,把自己的一些体会简单举个例子,详细的东西还是需要自己慢慢体会的,比如 from a , b where a .id= b .id(+) and b .name=&apos;a&apos; 这个 b . name 没有 + 号则相当于普通的内连接 ( 先外连接后过滤,这个准确点,比如 b .name is null 那么和普通内连接还是有所不同的 ) , -- 用连接键 is null 判断,不用考虑 null 问题,因为选择的是不配的值, rowid is null 也可以,他非连接键只能选择 NOT NULL 约束的 ?? 不对, 这个是过滤,所有没有匹配列都为 NULL INSERT INTO a VALUES( 1 ,&apos;a&apos;); SELECT a .ID, b .ID FROM a , b WHERE a .ID= b .ID(+) UNION ALL SELECT a .ID, b .ID FROM a , b WHERE a .ID(+)= b .ID AND a .ID IS NULL; -- 下面的是找以 id 连接在 b 中不在 a 中的数据,相当于 SELECT a .ID, b .ID FROM a , b WHERE a .ID(+)= b .ID AND a .ID IS NULL; ==&gt; SELECT a .ID, b .ID FROM a RIGHT JOIN b ON a .ID= b .ID WHERE a .ID IS NULL; SELECT a .ID, b .ID FROM a , b WHERE a .ID(+)= b .ID AND a .ID(+) IS NULL; ===&gt; SELECT a .ID, b .ID FROM a RIGHT JOIN b ON a .ID= b .ID AND a .ID IS NULL;
  12. 73993 * 3 + 295, 类似嵌套循环,效率很低,目标表必须做驱动表 全表更新 DROP TABLE a ; DROP TABLE b ; CREATE TABLE a AS SELECT * FROM all_objects ; CREATE TABLE b AS SELECT * FROM user_objects ; CREATE INDEX idx_a ON a ( object_id ); CREATE INDEX idx_b ON b ( object_id ); BEGIN dbms_stats . gather_table_stats ( ownname =&gt; USER, tabname =&gt; &apos;a&apos;,cascade =&gt; TRUE); dbms_stats . gather_table_stats ( ownname =&gt; USER, tabname =&gt; &apos;b&apos;,cascade =&gt; TRUE); END; SELECT COUNT(*) FROM a ; --73993 SELECT COUNT(*) FROM b ; --2301 UPDATE a SET a . object_name =(SELECT b . object_name FROM b WHERE a . object_id = b . object_id ); UPDATE a SET a . object_name =(SELECT b . object_name FROM b WHERE a . object_id = b . object_id ) WHERE EXISTS (SELECT 1 FROM b WHERE a . object_id = b . object_id ); MERGE INTO a USING b ON a . object_id = b . object_id WHEN MATCHED THEN UPDATE a . object_name = b . object_name ; ALTER TABLE b ADD CONSTRAINTS uk_b UNIQUE( object_id ); UPDATE (SELECT a . object_name aname , b . object_name bname FROM a , b WHERE a . object_id = b . object_id ) SET aname = bname ; SELECT 73993 * 3 + 295 FROM dual ;
  13. 多次访问 B 表
  14. Merge 一般不错,但是 merge 也有限制,比如连接条件不能返回多行
  15. BYPASS_UJVC 11g 不能用了 必须保证 b 的连接键值有唯一约束 为了保证视图是可更新的,其定义中不 能包含以下语法结构( construct ): ● 集合操作符( set operator ) ● DISTINCT 操作符 ● 聚合函数( aggregate function )或分析型函数( analytic function ) ● GROUP BY , ORDER BY , CONNECT BY ,或 START WITH 字句 ● 在 SELECT 之后的列表中使用 collection expression ● 在 SELECT 之后的列表中使用子查询( subquery ) ● 连接( join )(但是有例外情况)
  16. In 和 exists 等价,因为 in 没有 null 的问题,从计划可以看出来
  17. Exists 一样,只要 semi join 与 or 连用就走不了 semi,filter 效率经常低
  18. ALTER TABLE a MODIFY object_name NULL; ALTER TABLE b MODIFY object_name NULL; 对于 not exists 是 anti join,not in 主要看前后的都要有 not null 约束 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 ) SELECT * FROM a WHERE a . object_name NOT IN (SELECT b . object_name FROM b WHERE b . object_name IS NOT NULL); -- 这个菜是 anti join SELECT * 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);
  19. ALTER TABLE a MODIFY object_name NULL; ALTER TABLE b MODIFY object_name NULL; 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 ) OR a . object_id &lt; 80000 ; SELECT * FROM a WHERE a . object_name IN (SELECT b . object_name FROM b ) OR a . object_id &lt; 80000 ; SELECT * FROM a WHERE a . object_name IN (SELECT b . object_name FROM b ) OR a . object_id &lt; (SELECT b . object_id FROM b WHERE b . object_id = 80000 ); SELECT * FROM a WHERE a . object_name IN (SELECT b . object_name FROM b ) UNION SELECT * FROM a WHERE a . object_id &lt; (SELECT b . object_id FROM b WHERE b . object_id = 80000 ); /*+precompute_subquery */ SELECT * FROM a WHERE a . object_name NOT IN (SELECT b . object_name FROM b ); SELECT /*+optimizer_features_enable(&apos;9.0.0&apos;)*/ * 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 ) SELECT * FROM a WHERE a . object_name NOT IN (SELECT b . object_name FROM b WHERE b . object_name IS NOT NULL); -- 这个菜是 anti join SELECT * 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); SELECT * FROM a WHERE NOT EXISTS (SELECT 1 FROM b WHERE a . object_name = b . object_name ) OR a . object_id &lt; 80000 ; SELECT * FROM a WHERE NOT EXISTS (SELECT 1 FROM b WHERE a . object_name = b . object_name ) UNION SELECT * FROM a WHERE a . object_id &lt; 80000 ;
  20. 一定情况下也可以考虑外连接
  21. 当然也可以通过索引来消除排序 就是相互匹配