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()

实验验证:

1.不同表连接的表访问次数验证

2.不同表连接的驱动顺序区别

3.不同表连接的排序情况分析

4.不同表连接的限制场景对比

5.不同表连接和索引的关系

首先,准备两张表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的更多相关文章

  1. SQL Tuning 基础概述10 - 体会索引的常见执行计划

    在<SQL Tuning 基础概述05 - Oracle 索引类型及介绍>的1.5小节,提到了几种"索引的常见执行计划": INDEX FULL SCAN:索引的全扫描 ...

  2. SQL Tuning 基础概述10

    在<SQL Tuning 基础概述05 - Oracle 索引类型及介绍>的1.5小节,提到了几种"索引的常见执行计划": INDEX FULL SCAN:索引的全扫描 ...

  3. SQL Tuning 基础概述08 - SQL Tuning Advisor

    SQL调优顾问 SQL Tuning Advisor的使用案例: 1.构建测试表T 2.定义调整任务 3.修改调整任务参数 4.执行调整任务 5.监控调整任务 6.查看调整任务建议 7.删除调整任务 ...

  4. SQL Tuning 基础概述01 - Autotrace的设定

    1.autotrace的设定 SQL> set autotrace Usage: SET AUTOT[RACE] {OFF | ON | TRACE[ONLY]} [EXP[LAIN]] [ST ...

  5. SQL Tuning 基础概述04 - Oracle 表的类型及介绍

    Tables A table describes an entity such as employees. You define a table with a table name, such as ...

  6. SQL Tuning 基础概述09 - SQL Access Advisor

    Oracle官方文档对SQL Access Advisor的描述如下: SQL Access Advisor, which is a tuning tool that provides advice ...

  7. SQL Tuning 基础概述05 - Oracle 索引类型及介绍

    一.B-Tree索引 三大特点:高度较低.存储列值.结构有序 1.1利用索引特性进行优化 外键上建立索引:不但可以提升查询效率,而且可以有效避免锁的竞争(外键所在表delete记录未提交,主键所在表会 ...

  8. SQL Tuning 基础概述07 - SQL Joins

    N多年之前,刚刚接触SQL的时候,就被多表查询中的各种内连接,外连接,左外连接,右外连接等各式各样的连接弄的晕头转向. 更坑的是书上看到的各种表连接还有两种不同的写法, 比如对于表A,表B的查询 1, ...

  9. SQL Tuning 基础概述02 - Explain plan的使用

    1.explain plan的使用 SQL> explain plan for delete from t_jingyu; Explained. SQL> select * from ta ...

随机推荐

  1. wepack+sass+vue 入门教程(二)

    六.新建webpack配置文件 webpack.config.js 文件整体框架内容如下,后续会详细说明每个配置项的配置 webpack.config.js直接放在项目demo目录下 module.e ...

  2. Elasticsearch 5.0 中term 查询和match 查询的认识

    Elasticsearch 5.0 关于term query和match query的认识 一.基本情况 前言:term query和match query牵扯的东西比较多,例如分词器.mapping ...

  3. .Net多线程编程—预备知识

    1 基本概念 共享内存的多核架构:一个单独的封装包内封装了多个互相连接的未处理器,且所有内核都可以访问主内存.共享内存的多核系统的一些微架构,例如内核暂停功能,超频. 内核暂停功能:当使用内核不多的时 ...

  4. Anders Hejlsberg 技术理想架构开发传奇

    Anders Hejlsberg(安德斯-海森博格) 坐在自己的办公室,双眼直直的盯着前方.他要做一个决定,决定自己未来的命运和理想.这是1996年一个普通的下午,几个小时前,他刚与比尔-盖茨结束了 ...

  5. 玩转spring boot——结合jQuery和AngularJs

    在上篇的基础上 准备工作: 修改pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi=&q ...

  6. AspNetPager分页控件样式的使用

    分页是Web应用程序中最常用到的功能之一,AspNetPager  简单实用,应用到项目后台中,棒极了! 自定义样式: <style type="text/css"> ...

  7. javascript有用小功能总结(未完待续)

    1)javascript让页面标题滚动效果 代码如下: <title>您好,欢迎访问我的博客</title> <script type="text/javasc ...

  8. Configure a bridged network interface for KVM using RHEL 5.4 or later?

    environment Red Hat Enterprise Linux 5.4 or later Red Hat Enterprise Linux 6.0 or later KVM virtual ...

  9. ASP.NET Aries JSAPI 文档说明:AR.DataGrid、AR.Dictionary

    AR.Global 文档 1:对象或属性: 名称 类型 说明 DG 对象 DataGrid操作对象 //datagrid集合,根据ID取出DataGrid对象,将Json当数组用. Items: ne ...

  10. Xamarin.Android活动的生命周期

    一.前言 用过Android手机的人一定会发现一种现象,当你把一个应用置于后台后,一段时间之后在打开就会发现应用重新打开了,但是之前的相关的数据却没有丢失.可以看出app的“生命”是掌握在系统手上的, ...