1 排序合并连接SMJ

Sort merge join

排序合并总结:

1 通常情况下,排序合并连接的效率远不如hash join,前者适用范围更广,hj只使用于等值连接,smj范围更广(<,>,>=,<=)

2 通常情况下,smj并不适合OLTP系统,排序操作是非常昂贵的操作,

2 嵌套循环连接NL

优化器会根据一定的规则来确定表T1,T2谁是驱动表,谁是被驱动表,驱动表用于外层循环,被驱动表用于内存循环,这里假设驱动表时T1,被驱动表时T2

目标sql中指定的谓词条件去访问T1,得到的结果集为1

然后遍历驱动结果集1同时遍历被驱动表T2,即先取出1中的第一条记录,接着遍历T2并按照条件去判断T2中是否存在配匹的记录,然后在取出1中的第二条记录。。。。

嵌套循环总结:

  1 如果t1对应的驱动结果集较少,同时t2的连接列上又有唯一性索引,则效率会很高

  2 只要驱动结果集很少就具备嵌套循环的前提条件

  3 嵌套循环可以实现快速响应,即可以第一时间返回经过连接且满足条件的记录,而不必等待所有的连接操作全部做完才返回连接结果

如果使用了nl连接,并且t2的连接列上index,那么oracle访问该index是通常会使用单块读,则t1的返回n条结果,就会是t2访问该index n次,如果要回表,

则会回表n次,这就使得不在index 或者data buffer  cache中的数据,发生物理I/O,

Oracle 11g使用了向量I/O,提高nl的连接效率

nested loop
    outer table             --驱动表
    inner table

The second picture, shown in Figure 11-2, includes a representation of working through

an index on the second table, because an index is usually involved in this way when there is a

nested loop around.


create table t1 (col1 number, col2 varchar2(1)); create table t2 (col2 varchar2(1), col3 varchar2(2)); insert into t1 values(1,'A');
insert into t1 values(2,'B');
insert into t1 values(3,'C');
insert into t2 values('A','A1');
insert into t2 values('B','B1');
insert into t2 values('D','D1');
Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bit Production
With the Partitioning, OLAP and Data Mining options SQL> set linesize 1000
SQL> set pagesize 1000
SQL> set timing on
SQL> set autot trace only
SP2-0158: unknown SET option "only"
SQL> set autotrace traceonly;
SQL> select t1.col1,t1.col2,t2.col3
2 from t1,t2
3 where t1.col2=t2.col2;
Elapsed: 00:00:00.04
Execution Plan
----------------------------------------------------------
Plan hash value: 2253255382
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3 | 60 | 4 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T2 | 1 | 5 | 1 (0)| 00:00:01 |
| 2 | NESTED LOOPS | | 3 | 60 | 4 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL | T1 | 3 | 45 | 3 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | IDX_T2 | 1 | | 0 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("T1"."COL2"="T2"."COL2")
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
13 consistent gets
0 physical reads
0 redo size
469 bytes sent via SQL*Net to client
337 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2 rows processed

  

3 哈希连接HJ

哈希连接是两个表在做连接时只要依靠哈希运算来得到结果集(仅适合CBO),在解析目标sql 时是否考虑哈希连接受限制与隐含参数(_HASH_JOIN_ENABLED),

默认值TRUE,如果值为false,强制使用hint,也是会走hj的

1 oracle会根据参数HASH_AREA_SIZE,DB_BLOCK_SIZE,_HASH_MULTIBLOCK_IO_COUNT来决定hash partition的数量,所有hash partition的集合称为Hash table,

2 表t1,t2在目标sql中的谓词条件后,得到结果集中的数据量较少的那个结果集会被oracle选为哈希连接的驱动结果集,假设t1的结果集1较少(驱动结果集),t2的结果2(被驱动结果集)

3 oracle会遍历结果集1,读取1中的每一条记录,并对每一条记录按照该记录t1中的连接列做哈希运算,

--小表在数据在指定谓词后做哈希运算放入pga中(超过放入temp),大表数据按照连接列做哈希运算,然后大表去配匹pga中的值,遍历完为止

哈希连接的优缺点:

  1 哈希连接不一定会排序,大多数情况下不需要排序

    2 哈希连接的驱动表所对应的连接列的可选择性尽可能的好,会影响hash bucket中的记录数,哈希连接中,遍历hash bucket的动作发生在pga工作区中,不消耗逻辑读,

  3 哈希连接适用于CBO,等值连接

  4 哈希连接适合大表跟小表的连接,2个表做哈希连接,在指定了谓词后的sql中得到的数量较少的结果集所对应的hash table能完全容纳在pga中,则效率会很高。

SQL> select /*+ leading (t1) use_hash(t2) */
2 t1.col1,t1.col2,t2.col3
3 from t1,t2
4 where t1.col2=t2.col2;
Elapsed: 00:00:00.25
Execution Plan
----------------------------------------------------------
Plan hash value: 1838229974
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3 | 60 | 7 (15)| 00:00:01 |
|* 1 | HASH JOIN | | 3 | 60 | 7 (15)| 00:00:01 |
| 2 | TABLE ACCESS FULL| T1 | 3 | 45 | 3 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| T2 | 3 | 15 | 3 (0)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T1"."COL2"="T2"."COL2")
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
7 recursive calls
0 db block gets
32 consistent gets
0 physical reads
0 redo size
469 bytes sent via SQL*Net to client
337 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
2 rows processed

4笛卡尔连接cross join

2个表在做连接是,没有指定任何连接条件的连接

SQL> select
2 t1.col1,t1.col2,t2.col3
3 from t1,t2; 9 rows selected. Elapsed: 00:00:00.03 Execution Plan
----------------------------------------------------------
Plan hash value: 787647388 -----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 9 | 162 | 8 (0)| 00:00:01 |
| 1 | MERGE JOIN CARTESIAN| | 9 | 162 | 8 (0)| 00:00:01 |
| 2 | TABLE ACCESS FULL | T1 | 3 | 45 | 3 (0)| 00:00:01 |
| 3 | BUFFER SORT | | 3 | 9 | 5 (0)| 00:00:01 |
| 4 | TABLE ACCESS FULL | T2 | 3 | 9 | 2 (0)| 00:00:01 |
-----------------------------------------------------------------------------

5 反连接Anti join

做子查询展开时,oracle会经常把那些外部where条件为 no exists,not in ,<>all的子查询转换成对应的反连接

SQL> select * from t1
2 where t1.col2 not in (select col2 from t2);
Elapsed: 00:00:00.01
Execution Plan
----------------------------------------------------------
Plan hash value: 895956251
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 15 | 5 (0)| 00:00:01 |
|* 1 | FILTER | | | | | |
| 2 | TABLE ACCESS FULL| T1 | 3 | 45 | 3 (0)| 00:00:01 |
|* 3 | TABLE ACCESS FULL| T2 | 3 | 6 | 2 (0)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter( NOT EXISTS (SELECT /*+ */ 0 FROM "T2" "T2" WHERE
LNNVL("COL2"<>:B1)))
3 - filter(LNNVL("COL2"<>:B1))
SQL> select * from t1
2 where not exists (select 1 from t2 where t1.col2=t2.col2);
Elapsed: 00:00:00.01
Execution Plan
----------------------------------------------------------
Plan hash value: 1534930707
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 17 | 3 (0)| 00:00:01 |
| 1 | NESTED LOOPS ANTI | | 1 | 17 | 3 (0)| 00:00:01 |
| 2 | TABLE ACCESS FULL| T1 | 3 | 45 | 3 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | IDX_T2 | 3 | 6 | 0 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("T1"."COL2"="T2"."COL2")
alter session set "_optimizer_null_aware_antijoin"=false

6 半连接semi join

半连接跟普通的连接不同,半连接会去重?

对子查询展开,exists,in等

SQL> select * from t1
2 where t1.col2 in (select col2 from t2);
Elapsed: 00:00:00.01
Execution Plan
----------------------------------------------------------
Plan hash value: 3783859632
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3 | 51 | 3 (0)| 00:00:01 |
| 1 | NESTED LOOPS SEMI | | 3 | 51 | 3 (0)| 00:00:01 |
| 2 | TABLE ACCESS FULL| T1 | 3 | 45 | 3 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | IDX_T2 | 3 | 6 | 0 (0)| 00:00:01 |
----------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 3 - access("T1"."COL2"="COL2")
SQL> select * from t1
2 where exists (select 1 from t2 where t1.col2=t2.col2);
Elapsed: 00:00:00.01
Execution Plan
----------------------------------------------------------
Plan hash value: 3783859632
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3 | 51 | 3 (0)| 00:00:01 |
| 1 | NESTED LOOPS SEMI | | 3 | 51 | 3 (0)| 00:00:01 |
| 2 | TABLE ACCESS FULL| T1 | 3 | 45 | 3 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | IDX_T2 | 3 | 6 | 0 (0)| 00:00:01 |
----------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 3 - access("T1"."COL2"="T2"."COL2")

总结一下

  • 在哪种情况下用哪种连接方法比较好:

A)排序合并连接(Sort Merge Join, SMJ):

a) 对于非等值连接,这种连接方式的效率是比较高的。

b) 如果在关联的列上都有索引,效果更好。

c) 对于将2个较大的表源做连接,该连接方法比NL连接要好一些。

B)嵌套循环(Nested Loops, NL):

a) 如果驱动表(外部表)比较小,并且在被驱动表(内部表)上有唯一索引,或有高选择性非唯一索引时,使用这种方法可以得到较好的效率。

b)嵌套循环连接有其它连接方法没有的的一个优点是:可以先返回已经连接的行,而不必等待所有的连接操作处理完才返回数据,这可以实现快速的响应时间。

C)哈希连接(Hash Join, HJ):

a) 这种方法是在oracle7后来引入的,使用了比较先进的连接理论,一般来说,其效率应该好于其它2种连接,但是这种连接只能用在CBO优化器中,

    而且需要设置合适的hash_area_size参数,才能取得较好的性能。

b) 在2个较大的表源之间连接时会取得相对较好的效率,在一个表源较小时则能取得更好的效率。

c) 只能用于等值连接中

Oracle常见的表连接的方法的更多相关文章

  1. Oracle 导出空表的新方法(彻底解决)

    背景 使用Exp命令在oracle 11g 以后不导出空表(rowcount=0),是最近在工作中遇到一个很坑的问题,甚至已经被坑了不止一次,所以这次痛定思痛,准备把这个问题彻底解决.之所以叫新方法, ...

  2. 转载 ORACLE中实现表变量的方法

    源文地址:http://blog.itpub.net/750077/viewspace-2134222/ 经常看到SQLSERVER 中用表变量类型的方式就能做到缓存一个比较大的中间结果, 然后再对这 ...

  3. 移动Oracle的用户表空间文件方法

    原文:http://www.linuxidc.com/Linux/2014-07/104702.htm 1.以sys用户登录        sqlplus /nologSQL>connect s ...

  4. Oracle数据库锁表的查询方法以及解锁的方法

    1,锁表语句简单查询方法   select t2.username,t2.sid,t2.serial#,t2.logon_time from v$locked_object t1,v$session ...

  5. oracle三种表连接方式

    1. 排序合并连接(Sort Merge Join) 排序合并连接的执行过程如下所示: * 将每个行源的行按连接谓词列排序 * 然后合并两个已排序的行源,并返回生成的行源 例如: select * f ...

  6. 查看oracle是否锁表以及解决方法

    Oracle数据库操作中,我们有时会用到锁表查询以及解锁和kill进程等操作,那么这些操作是怎么实现的呢?本文我们主要就介绍一下这部分内容.(1)锁表查询的代码有以下的形式: select count ...

  7. Oracle三大经典表连接适用情况

    1.1环境准备 1.2 Nested Loops Join 从上面的试验来看,nested loop jion基本上是没有限制的,可以支持所有的运算. 1.3 Hash Join 1.4 Merge ...

  8. Oracle 优化器_表连接

    概述 在写SQL的时候,有时候涉及到的不仅只有一个表,这个时候,就需要表连接了.Oracle优化器处理SQL语句时,根据SQL语句,确定表的连接顺序(谁是驱动表,谁是被驱动表及 哪个表先和哪个表做链接 ...

  9. ORACLE 表连接详解

    在ORACLE中,表连接方式主要有:内连接,外连接,自连接: 内连接: 这是最常用的连接查询 SELECT * FROM A INNER JOIN B ON A.ID=B.ID SELECT * FR ...

随机推荐

  1. ACM International Collegiate Programming Contest, Tishreen Collegiate Programming Contest (2018) Syria, Lattakia, Tishreen University, April, 30, 2018

    ACM International Collegiate Programming Contest, Tishreen Collegiate Programming Contest (2018) Syr ...

  2. angularjs地址栏传参

    1:路由定义参数 2.controller 3. 4.目标得到参数值

  3. linux rpm 卸载,简单说明

    平时Linux卸载文件总是遇到卸载不干净,各种依赖什么的,今天又是搞这玩意,就记录下一个比较常规的方法. 一.查询包括某关键字的软件(这里以卸载openoffice为例) 查询包括office的软件 ...

  4. asp.net core mvc中如何把二级域名绑定到特定的控制器上

    由于公司的工作安排,一直在研究其他技术,所以一直没时间更新博客,今天终于可以停下手头的事情,写一些新内容了. 应用场景:企业门户网站会根据内容不同,设置不同的板块,如新浪有体育,娱乐频道,等等.有的情 ...

  5. javascript 对象简单介绍(一)

    JavaScript 对象JavaScript 中的所有事物都是对象:字符串.数值.数组.函数...此外,JavaScript 允许自定义对象.所有事物都是对象JavaScript 提供多个内建对象, ...

  6. 如何用VC编写供PB调用的DLL

    和编写一般的DLL方法相同,需要注意以下两点: (1)调用约定 c函数有_stdcall._cdecl._fastcall等多种调用约定,调用约定用来说明函数参数的压栈顺序和由谁(函数自身还是调用者) ...

  7. hdu4185

    题解:每两个联通的油井建边 然后二分图最大匹配 最后答案除以2 代码: #include<cstdio> #include<cmath> #include<cstring ...

  8. Ceph与OpenStack整合(仅为云主机提供云盘功能)

    1. Ceph与OpenStack整合(仅为云主机提供云盘功能) 创建: linhaifeng,最新修改: 大约1分钟以前 ceph ceph osd pool create volumes 128 ...

  9. pg_buffercache

    查看缓冲区缓存的内容: create extension pg_buffercache; select c.relname, count(1) as buffers from pg_class c j ...

  10. .Net WebApi 添加Swagger

    前言 随着互联网技术的发展,现在的网站架构基本都由原来的后端渲染,变成了:前端渲染.先后端分离的形态,而且前端技术和后端技术在各自的道路上越走越远. 前端和后端的唯一联系,变成了API接口:API文档 ...