SQL Tuning 基础概述06 - 表的关联方式:Nested Loops Join,Merge Sort Join & Hash Join
nested loops join(嵌套循环)
驱动表返回几条结果集,被驱动表访问多少次,有驱动顺序,无须排序,无任何限制。
驱动表限制条件有索引,被驱动表连接条件有索引。
hints:use_nl()
merge sort join(排序合并)
驱动表和被驱动表都是最多访问1次,无驱动顺序,需要排序(SORT_AREA_SIZE),连接条件是<>或like导致无法使用。
在连接条件上建立索引可以消除一张表的排序。
hints:use_merge()
hash join(哈希连接)
驱动表和被驱动表都是最多访问1次,有驱动顺序,无须排序(HASH_AREA_SIZE但是会消耗内存用于建HASH表),连接条件是<> > < 或like导致无法使用。
索引列在表连接中无特殊要求,与单表情况相同。
hints:use_hash()
实验验证:
首先,准备两张表t1,t2,分别初始化随机插入100条和100,000条数据:
drop table t1 cascade constraints purge;
drop table t2 cascade constraints purge;
create table t1( id number not null, n number, contents varchar2(4000) );
create table t2( id number not null, t1_id number not null, n number, contents varchar2(4000) );
execute dbms_random.seed(0);
insert into t1 select rownum, rownum, dbms_random.string('a',50) from dual connect by level <= 100 order by dbms_random.random;
commit;
insert into t2 select rownum, rownum, rownum, dbms_random.string('b',50) from dual connect by level <= 100000 order by dbms_random.random;
commit;
select count(1) from t1;
select count(1) from t2;
1.不同表连接的表访问次数验证:
set linesize 1000 pagesize 200
alter session set statistics_level = all;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
1.1 nested loops join:
select /*+ leading(t1)use_nl(t2) */ * from t1, t2 where t1.id = t2.t1_id; select /*+ leading(t1)use_nl(t2) */ * from t1, t2 where t1.id = t2.t1_id and t1.n in(17,19); select /*+ leading(t1)use_nl(t2) */ * from t1, t2 where t1.id = t2.t1_id and t1.n = 19; select /*+ leading(t1)use_nl(t2) */ * from t1, t2 where t1.id = t2.t1_id and t1.n = 99999999;
1.2 hash join:
select /*+ leading(t1)use_hash(t2) */ * from t1, t2 where t1.id = t2.t1_id; select /*+ leading(t1)use_hash(t2) */ * from t1, t2 where t1.id = t2.t1_id and t1.n in(17,19); select /*+ leading(t1)use_hash(t2) */ * from t1, t2 where t1.id = t2.t1_id and t1.n = 19; select /*+ leading(t1)use_hash(t2) */ * from t1, t2 where t1.id = t2.t1_id and t1.n = 99999999; select /*+ leading(t1)use_hash(t2) */ * from t1, t2 where t1.id = t2.t1_id and 1 = 2;
1.3 merge sort join
select /*+ ordered use_merge(t2) */ * from t1, t2 where t1.id = t2.t1_id;
2.不同表连接的驱动顺序区别:
2.1 nested loops join
select /*+ leading(t1)use_nl(t2) */ * from t1, t2 where t1.id = t2.t1_id and t1.n = 19; select /*+ leading(t2)use_nl(t1) */ * from t1, t2 where t1.id = t2.t1_id and t1.n = 19;
2.2 hash join
select /*+ leading(t1)use_hash(t2) */ * from t1, t2 where t1.id = t2.t1_id and t1.n = 19; select /*+ leading(t2)use_hash(t1) */ * from t1, t2 where t1.id = t2.t1_id and t1.n = 19;
2.3 merge sort join
select /*+ leading(t1)use_merge(t2) */ * from t1, t2 where t1.id = t2.t1_id and t1.n = 19; select /*+ leading(t2)use_merge(t1) */ * from t1, t2 where t1.id = t2.t1_id and t1.n = 19;
说到不同表连接表的驱动顺序,网上也有一个普遍流行的观点,就是小表作为驱动表。其实通过上面的实验可以发现这样的描述是不准确的。
正确地描述应该是:对于nested loops join和hash join来说,小的结果集先访问,大的结果集后访问(即与表的大小没有关系,与具体sql返回的结果集大小有关);而对于merge sort join 来说,先访问谁效率都是一样的。
3.不同表连接的排序情况分析:
嵌套循环,不排序;
hash连接,消耗内存建立hash表;
排序合并,需要排序。
开发人员需要注意不要取多余的字段参与排序:
select /*+ leading(t2)use_merge(t1) */ * from t1, t2 where t1.id = t2.t1_id and t1.n = 19; select /*+ leading(t2)use_merge(t1) */ t1.id from t1, t2 where t1.id = t2.t1_id and t1.n = 19;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
4.不同表连接的限制场景对比:
4.1 hash join不支持<> > < like连接条件
select /*+ leading(t1)use_hash(t2) */ * from t1, t2 where t1.id = t2.t1_id and t1.n = 19; select /*+ leading(t1)use_hash(t2) */ * from t1, t2 where t1.id <> t2.t1_id and t1.n = 19; select /*+ leading(t1)use_hash(t2) */ * from t1, t2 where t1.id > t2.t1_id and t1.n = 19; select /*+ leading(t1)use_hash(t2) */ * from t1, t2 where t1.id < t2.t1_id and t1.n = 19; select /*+ leading(t1)use_hash(t2) */ * from t1, t2 where t1.id like t2.t1_id and t1.n = 19;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
4.2 merge sort join不支持<> like 连接方式
select /*+ leading(t1)use_merge(t2) */ * from t1, t2 where t1.id = t2.t1_id and t1.n = 19; select /*+ leading(t1)use_merge(t2) */ * from t1, t2 where t1.id <> t2.t1_id and t1.n = 19; select /*+ leading(t1)use_merge(t2) */ * from t1, t2 where t1.id > t2.t1_id and t1.n = 19; select /*+ leading(t1)use_merge(t2) */ * from t1, t2 where t1.id < t2.t1_id and t1.n = 19; select /*+ leading(t1)use_merge(t2) */ * from t1, t2 where t1.id like t2.t1_id and t1.n = 19;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
4.3 nested loops join 所有都支持
从上面实验结果来看,不能走hash和merge的表连接条件,都会走nested loops join。
5.不同表连接和索引的关系:
5.1 nested loops join
驱动表的限制条件建立索引,被驱动表的连接条件建立索引。
create index idx_t1_n on t1(n); create index idx_t2_t1_id on t2(t1_id); select /*+ leading(t1)use_nl(t2) */ * from t1, t2 where t1.id = t2.t1_id and t1.n = 19; select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
5.2 hash join
select /*+ leading(t1)use_hash(t2) */ * from t1, t2 where t1.id = t2.t1_id and t1.n = 19; select * from t1, t2 where t1.id = t2.t1_id and t1.n = 19;
一般查询没有合适索引,Oracle都会选择用hash join的表连接。
5.3 merge sort join
create index idx_t1_id on t1(id);
select /*+ ordered use_merge(t2) */ * from t1, t2 where t1.id = t2.t1_id and t1.n = 19;
Oracle 10g版本,在连接条件建立索引可以消除merge sort join表连接的一张表的排序操作。(虽然在两张表的连接条件都建立了索引,却只能消除一张表的排序操作)
注:本文为《收获,不止Oracle》表连接一章的总结笔记。
SQL Tuning 基础概述06 - 表的关联方式:Nested Loops Join,Merge Sort Join & Hash Join的更多相关文章
- SQL Tuning 基础概述10 - 体会索引的常见执行计划
在<SQL Tuning 基础概述05 - Oracle 索引类型及介绍>的1.5小节,提到了几种"索引的常见执行计划": INDEX FULL SCAN:索引的全扫描 ...
- SQL Tuning 基础概述10
在<SQL Tuning 基础概述05 - Oracle 索引类型及介绍>的1.5小节,提到了几种"索引的常见执行计划": INDEX FULL SCAN:索引的全扫描 ...
- SQL Tuning 基础概述08 - SQL Tuning Advisor
SQL调优顾问 SQL Tuning Advisor的使用案例: 1.构建测试表T 2.定义调整任务 3.修改调整任务参数 4.执行调整任务 5.监控调整任务 6.查看调整任务建议 7.删除调整任务 ...
- SQL Tuning 基础概述01 - Autotrace的设定
1.autotrace的设定 SQL> set autotrace Usage: SET AUTOT[RACE] {OFF | ON | TRACE[ONLY]} [EXP[LAIN]] [ST ...
- SQL Tuning 基础概述04 - Oracle 表的类型及介绍
Tables A table describes an entity such as employees. You define a table with a table name, such as ...
- SQL Tuning 基础概述09 - SQL Access Advisor
Oracle官方文档对SQL Access Advisor的描述如下: SQL Access Advisor, which is a tuning tool that provides advice ...
- SQL Tuning 基础概述05 - Oracle 索引类型及介绍
一.B-Tree索引 三大特点:高度较低.存储列值.结构有序 1.1利用索引特性进行优化 外键上建立索引:不但可以提升查询效率,而且可以有效避免锁的竞争(外键所在表delete记录未提交,主键所在表会 ...
- SQL Tuning 基础概述07 - SQL Joins
N多年之前,刚刚接触SQL的时候,就被多表查询中的各种内连接,外连接,左外连接,右外连接等各式各样的连接弄的晕头转向. 更坑的是书上看到的各种表连接还有两种不同的写法, 比如对于表A,表B的查询 1, ...
- SQL Tuning 基础概述02 - Explain plan的使用
1.explain plan的使用 SQL> explain plan for delete from t_jingyu; Explained. SQL> select * from ta ...
随机推荐
- js学习笔记:操作iframe
iframe可以说是比较老得话题了,而且网上也基本上在说少用iframe,其原因大致为:堵塞页面加载.安全问题.兼容性问题.搜索引擎抓取不到等等,不过相对于这些缺点,iframe的优点更牛,跨域请求. ...
- C#异步编程(一)
异步编程简介 前言 本人学习.Net两年有余,是第一次写博客,虽然写的很认真,当毕竟是第一次,肯定会有很多不足之处, 希望大家照顾照顾新人,有错误之处可以指出来,我会虚心接受的. 何谓异步 与同步相对 ...
- 匹夫细说C#:庖丁解牛迭代器,那些藏在幕后的秘密
0x00 前言 在匹夫的上一篇文章<匹夫细说C#:不是“栈类型”的值类型,从生命周期聊存储位置>的最后,匹夫以总结和后记的方式涉及到一部分迭代器的知识.但是觉得还是不够过瘾,很多需要说清楚 ...
- 关于Raid0,Raid1,Raid5,Raid10的总结
RAID0 定义: RAID 0又称为Stripe或Striping,它代表了所有RAID级别中最高的存储性能.RAID 0提高存储性能的原理是把连续的数据分散到多个磁盘上存取,这样,系统有数据请求就 ...
- CRL快速开发框架系列教程十一(大数据分库分表解决方案)
本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...
- [开发笔记]GCC 分支预测优化
#define likely(x) __builtin_expect(!!(x),1)#define unlikely(x) __builtin_expect(!!(x),0) 用于优化在做分支判断的 ...
- java springMVC SSM 操作日志 4级别联动 文件管理 头像编辑 shiro redis
A 调用摄像头拍照,自定义裁剪编辑头像 B 集成代码生成器 [正反双向](单表.主表.明细表.树形表,开发利器)+快速构建表单; 技术:313596790freemaker模版技术 ,0个代码不用写 ...
- 一些关于Linux入侵应急响应的碎碎念
近半年做了很多应急响应项目,针对黑客入侵.但疲于没有时间来总结一些常用的东西,寄希望用这篇博文分享一些安全工程师在处理应急响应时常见的套路,因为方面众多可能有些杂碎. 个人认为入侵响应的核心无外乎四个 ...
- .NET跨平台之旅:数据库连接字符串写法引发的问题
最近在一个ASP.NET Core站点中遇到一个奇怪问题.当用dotnet run命令启动站点后,开始的一段时间请求执行速度超慢,有时要超过20秒,有时甚至超过1分钟,日志中会记录这样的错误: Sys ...
- Xamarin.Android之ActionBar与菜单
一.选项卡 如今很多应用都会使用碎片以便在同一个活动中能够显示多个不同的视图.在Android 3.0 以上的版本中,我们已经可以使用ActionBar提供的Tab来实现这种效果,而不需要我们自己去实 ...