PLSQL_性能优化系列02_Oracle Join关联
2014-09-25 Created By BaoXinjian
Oracle三种主要连接方式的比较
1. Hash Join
(1).概述
i. 读取一个表的资料,并将放置到内存中,并建立唯一关键字的位图索引
ii. 读取另一个表,和内存中表通过Hash算法进行比较
(2).适用对象
i. 大表连接小表
ii. 两个大表
2. Nested Loops
(1).概述
i. 循环外表记录
ii. 进行逐个比对和内标的连接是否符合条件
(2).适用对象
小表驱动大表,返回较少的结果集
3. Merge Join
(1).概述
i. 两个表进行table access full
ii. 对table access full的结果进行排序
iii. 进行merge join对排序结构进行合并
(2).适用对象
通过rowid访问数据
当sql访问多个表时,关联对sql效率就有很重要的影响。关联要考虑两个因素,join的类型和join的次序。
1. Nested Loop Join方式
1.1 适用条件
(1). 关联少量数据(rows),返回集小。
(2). 关联条件能高效访问第二张表(inner table)。高效访问的关联条件如'=',反之非高效的关联条件如'!=','>'等;inner table(即非驱动表)上要有索引。
因此比较适合OLTP系统,因为OLTP系统中一般返回数据量小,而且表上面索引较多。
1.2 实现步骤
(1). 优化器选择驱动表(driving table),指定其为outer table
(2). 指定另一张表为inner table(非驱动表)
(3). 根据outer table的每行记录的关联字段,来访问inner table。如下所示:
NESTED LOOPS
Outer_Loop
Inner_Loop
由于Nested Loop从outer table向inner table查询,关联的次序就比较重要了。
1.3 Nexted Loop Join的例子
2. Hash Join方式
2.1 适用条件
(1). 仅用于等值关联equijoin(如=);
(2). 满足下列任一条件:
大表关联
或者小表的大部分记录参与关联
2.2 实现机制
(1). 优化器选择较小的表,基于join key构建hash table。(驱动表)
(2). 扫描另外一张较大的表,并在hash table中搜寻关联行
如果内存足够,小表全部在内存中,这种情况是最优的,成本可估算为两张表各一次全表读。
如果内存不够,则小表的一部分可以放在temporary tablespace中(Temp表空间应足够大),以尽可能提高io速度。
2.3 Hash Join的例子
3. Sort merge join
3.1 适用情况
通常情况下hash join性能更好,但如果关联的数据已经排序或不需排序,则sort merge join性能会更好。
非等值关联(nonequi join,如<,> )时很有用,因为sort merge join在返回集很大时比nested loop性能好,而hash join又只能在equijoin中使用。
3.2 实现机制
(1). Sort操作:关联数据按照关联字段进行排序。如果数据本来就是排序的,就不需此操作
(2). Merge操作:经过排序的数据进行merge操作。
需要说明的是,sort merge join没有driving table的概念
4. 笛卡尔连接
无关联条件,应尽可能避免。
5. Outer Join
5.1 Simple Join的扩展
customers表称为preserved table,orders表称为optional table
5.2 Outer Join的扩展
- Left outer join
- Right outer join
- Full outer join
5.3 和普通join相比,outer join也可以是nested loop、hash join、sort merge等。但有一些不同之处:
1. Nested Loop Outer Join中,以preserved table作为驱动表,而不是像普通join基于cost来选择驱动表。
2. Full Outer Join(equijoin)在11g中,自动使用基于hash join的算法。执行计划中出现HASH JOIN FULL OUTER。
可以用HINT:NATIVE_FULL_OUTER_JOIN/NO_NATIVE_FULL_OUTER_JOIN来指定使用或不使用这一算法。
如果不使用,则Full Outer Jion的执行计划是Left Outer Join和Right Outer Jion的Union。
基本原则是:记录少的先关联,这样参与后续关联的记录数就会少。具体来说:
(1). 选择能排除掉最多记录的表作为driving table
(2). 剩余的表中,选选择有最好的filter的表(排除最多记录)作为首先参与关联的表
(3). 以此类推
看这个例子:
SELECT info
FROM taba a, tabb b, tabc c
WHERE a.acol BETWEEN 100 AND 200
AND b.bcol BETWEEN 10000 AND 20000
AND c.ccol BETWEEN 10000 AND 20000
AND a.key1 = b.key1
AND a.key2 = c.key2;
假设a表经过filter后记录最少,b次之,c记录最多。那么可以用a作为driving table,先与b关联,最后与c关联
1. 使用hint指定关联方式
Oracle优化器自动选择join的方式,但有时不是最优的,开发人员可使用hint来选择join方式,比较执行效率。
相关的hint有:
- USE_NL,USE_HASH,USE_MERGE
- Exists子句中,HASH_SJ,MERGE_SJ,NL_SJ
- Not in子句中,HASH_AJ,MERGE_AJ,NL_AJ
2. 使用hint指定关联次序
如果oracle优化器选择的关联次序不是你所希望的,可以用hint(leading和ordered)来指定。Ordered表示按照sql语句中表出现的先后次序,leading则可任意指定,更为通用。
Leading指定了driving table的选定次序。(在nested loop中,driving table就是outer table,在hash join中,是hash table。)
SELECT /*+ leading (a b c) */info
WHERE a.acol BETWEEN 100 AND 200
AND b.bcol BETWEEN 10000 AND 20000
AND c.ccol BETWEEN 10000 AND 20000
AND a.key1 = b.key1
AND a.key2 = c.key2;
3. Undocumented hint参数:swap_join_inputs
注意,上面例子中,a作为驱动表和b关联,关联结果作为驱动表,再和c关联。有时需要改变次序,如下面例子
SELECT /*+ leading (a b c)*/ info
WHERE a.key1 = b.key1
AND b.key2 = c.key2;
假如a 1000条,b 10万条,c 1万条。由于a和c表没有关联字段,因此a和b先关联,再和c关联。但a关联b产生2万条记录,和c关联时,希望以c为驱动表,能否实现呢?
在hash_join中可以用oracle的隐含hint参数swap_join_inputs实现:
SELECT /*+ leading (a b c) swap_join_inputs(c) */ info
WHERE a.key1 = b.key1
AND b.key2 = c.key2;
Thanks and Regards
参考:http://blog.itpub.net/18474/viewspace-1060728/
参考:metalink:How to switch the driving table in a hash join [ID 171940.1]
PLSQL_性能优化系列02_Oracle Join关联的更多相关文章
- PLSQL_性能优化系列14_Oracle High Water Level高水位分析
2014-10-04 Created By BaoXinjian 一.摘要 PLSQL_性能优化系列14_Oracle High Water Level高水位分析 高水位线好比水库中储水的水位线,用于 ...
- PLSQL_性能优化系列16_Oracle Tuning Analyze优化分析
2014-12-23 Created By BaoXinjian
- PLSQL_性能优化系列01_Oracle Index索引
2014-06-01 Created By BaoXinjian
- PLSQL_性能优化系列04_Oracle Optimizer优化器
2014-09-25 Created By BaoXinjian
- PLSQL_性能优化系列15_Oracle Explain Plan解析计划解读
2014-12-19 Created By BaoXinjian
- PLSQL_性能优化系列12_Oracle Index Anaylsis索引分析
2014-10-04 Created By BaoXinjian
- PLSQL_性能优化系列08_Oracle Insert / Direct Insert性能优化
2014-09-25 Created By BaoXinjian
- PLSQL_性能优化系列07_Oracle Parse Bind Variables解析绑定变量
2014-09-25 Created By BaoXinjian
- PLSQL_性能优化系列06_Oracle Soft Parse / Hard Parse软硬解析
2014-08-11 Createed By BaoXinjian
随机推荐
- leetcode 150. Evaluate Reverse Polish Notation ------ java
Evaluate the value of an arithmetic expression in Reverse Polish Notation. Valid operators are +, -, ...
- bzoj 1061 志愿者招募(最小费用最大流)
[Noi2008]志愿者招募 Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 3792 Solved: 2314[Submit][Status][Di ...
- away3d学习
http://www.cnblogs.com/flash3d/p/3403109.html M3U8文件简介:http://blog.sina.com.cn/s/blog_6cf7acdf0102v0 ...
- FreeSWITCH安装报错“You must install libyuv-dev to build mod_fsv”的解决方案
昨天下午安装FreeSWITCH时遇到该问题时,整了一个下午都没解决,也走了许多弯路.如果直接通过yum安装libyuv-devel时,会报错说找不到该安装包.后来又通过FreeSWITCH官网的网上 ...
- tomcat集群待整理
对于tomcat的集群有两种方式,这个主要是针对 session而言的.一种就是sticky模式,即黏性会话模式:另外一种就是session复制模式了.所谓sticky模式就是说同一个用户的访问 请求 ...
- ViewPager动态加载、删除页面
很多人在网上说ViewPager的PagerAdapter.notifyDataSetChanged()无效.刚开始我也这样认为,甚至被误导以为是真理. 后来,找了一下,在PagerAdatpar ...
- C# 大于屏幕的窗体
1.使用SetWindowPos就可以做到这一点,只是最后一个参数要选对. RECT windowRect = new RECT(); User32.GetWindowRect(MyForm2.Han ...
- Linux-实用的工具
1.Nethogs-查看进程占用带宽情况wget http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm # ...
- eclipse打包jar文件(含外部jar包)的方法
在项目发布前,使用eclipse导出普通的jar包时,如果配置不好,在运行命令Java -jar /test.jar 时可能会出现如下三类错误信息: 1.no main manifest attrib ...
- Effective Java 学习笔记----第7章 通用程序设计
第7章 通用程序设计 第29条 将局部变量的作用域最小化 使一个局部变量的作用域最小化,最有力的技术室在第一次使用它的地方声明. 第30条 了解和使用库 效率提高.如果你不知道库 ...