Sort merge join、Nested loops、Hash join(三种连接类型)
目前为止,典型的连接类型有3种:
Sort merge join(SMJ排序-合并连接):
首先生产driving table需要的数据,然后对这些数据按照连接操作关联列进行排序;然后生产probed table需要的数据,然后对这些数据按照与driving table对应的连接操作列进行排序;最后两边已经排序的行被放在一起执行合并操作。排序是一个费时、费资源的操作,特别对于大表。所以smj通常不是一个特别有效的连接方法,但是如果driving table和probed table都已经预先排序,则这种连接方法的效率也比较高。
Nested loops(NL嵌套循环):
连接过程就是将driving table和probed table进行一次嵌套循环的过程。就是用driving table的每一行去匹配probed table 的所有行。Nested loops可以先返回已经连接的行,而不必等待所有的连接操作处理完成才返回数据,这可以实现快速的响应时间。
Hash join(哈希连接):
较小的row source被用来构建hash table与bitmap,第二个row source用来被hashed,并与第一个row source生产的hash table进行匹配。以便进行进一步的连接。当被构建的hash table与bitmap能被容纳在内存中时,这种连接方式的效率极高。但需要设置合适的hash_area_size参数且只能用于等值连接中。
Cartesian product(笛卡尔积):表的每一行依次与另外一表的所有行匹配。
_______________________________________________________
实验:
SQL> create table segs as select * from dba_segments where owner='SYS';
Table created.
SQL> create table objts as select * from dba_objects where owner='SYS';
Table created.
SQL> select count(*) from segs;
COUNT(*)
----------
2355
SQL> select count(*) from objts;
COUNT(*)
----------
30967
SQL> create index idx_segs_name on segs(segment_name);
Index created.
SQL> create index idx_objts_name on objts(object_name);
Index created.
SQL> exec dbms_stats.gather_table_stats(user,'SEGS',cascade => true);
PL/SQL procedure successfully completed.
SQL> exec dbms_stats.gather_table_stats(user,'OBJTS',cascade => true);
PL/SQL procedure successfully completed.
作用:DBMS_STATS.GATHER_TABLE_STATS统计表,列,索引的统计信息.
DBMS_STATS.GATHER_TABLE_STATS的语法如下:
DBMS_STATS.GATHER_TABLE_STATS ( ownname VARCHAR2, tabname VARCHAR2, partname VARCHAR2, estimate_percent NUMBER, block_sample BOOLEAN, method_opt VARCHAR2, degree NUMBER, granularity VARCHAR2, cascade BOOLEAN, stattab VARCHAR2, statid VARCHAR2, statown VARCHAR2, no_invalidate BOOLEAN, force BOOLEAN);
参数说明:
ownname:要分析表的拥有者
tabname:要分析的表名.
partname:分区的名字,只对分区表或分区索引有用.
estimate_percent:采样行的百分比,取值范围[0.000001,100],null为全部分析,不采样. 常量:DBMS_STATS.AUTO_SAMPLE_SIZE是默认值,由oracle决定最佳取采样值.
block_sapmple:是否用块采样代替行采样.
method_opt:决定histograms信息是怎样被统计的.method_opt的取值如下:
for all columns:统计所有列的histograms.
for all indexed columns:统计所有indexed列的histograms.
for all hidden columns:统计你看不到列的histograms
for columns <list> SIZE <N> | REPEAT | AUTO | SKEWONLY:统计指定列的histograms.N的取值范围[1,254]; REPEAT上次统计过的histograms;AUTO由oracle决定N的大小;SKEWONLY multiple end-points with the same value which is what we define by "there is skew in the data
degree:决定并行度.默认值为null.
granularity:Granularity of statistics to collect ,only pertinent if the table is partitioned.
cascace:是收集索引的信息.默认为falase.
stattab指定要存储统计信息的表,statid如果多个表的统计信息存储在同一个stattab中用于进行区分.statown存储统计信息表的拥有者.以上三个参数若不指定,统计信息会直接更新到数据字典.
no_invalidate: Does not invalidate the dependent cursors if set to TRUE. The procedure invalidates the dependent cursors immediately if set to FALSE.
force:即使表锁住了也收集统计信息.
例子:
execute dbms_stats.gather_table_stats(ownname => 'owner',tabname => 'table_name' ,estimate_percent => null ,method_opt => 'for all indexed columns' ,cascade => true);
------------------------------------------------------------------------------------------------------------------------
自从Oracle8.1.5引入dbms_stats包,Experts们便推荐使用dbms_stats取代analyze。 理由如下
dbms_stats可以并行分析
dbms_stats有自动分析的功能(alter table monitor )
analyze 分析统计信息的不准确some times
1,2好理解,且第2点实际上在VLDB中是最吸引人的;3以前比较模糊,看了metalink236935.1 解释,analyze在分析Partition表的时候,有时候会计算出不准确的Global statistics .
原因是,dbms_stats会实在的去分析表全局统计信息(当指定参数);而analyze是将表分区(局部)的statistics 汇总计算成表全局statistics ,可能导致误差。
SQL> select * from segs, objts where segs.segment_name=objts.object_name;
2851 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 779051904
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2450 | 528K| 139 (1)| 00:00:02 |
|* 1 | HASH JOIN | | 2450 | 528K| 139 (1)| 00:00:02 |
| 2 | TABLE ACCESS FULL| SEGS | 2355 | 287K| 14 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| OBJTS | 30967 | 2903K| 125 (1)| 00:00:02 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("SEGS"."SEGMENT_NAME"="OBJTS"."OBJECT_NAME")
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
674 consistent gets
0 physical reads
0 redo size
228361 bytes sent via SQL*Net to client
2561 bytes received via SQL*Net from client
192 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2851 rows processed
SQL> select/*+use_merge(segs,objts)*/*from segs, objts where segs.segment_name=objts.object_name;
2851 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 2272228973
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2450 | 528K| | 822 (1)| 00:00:10 |
| 1 | MERGE JOIN | | 2450 | 528K| | 822 (1)| 00:00:10 |
| 2 | SORT JOIN | | 2355 | 287K| | 15 (7)| 00:00:01 |
| 3 | TABLE ACCESS FULL| SEGS | 2355 | 287K| | 14 (0)| 00:00:01 |
|* 4 | SORT JOIN | | 30967 | 2903K| 8136K| 807 (1)| 00:00:10 |
| 5 | TABLE ACCESS FULL| OBJTS | 30967 | 2903K| | 125 (1)| 00:00:02 |
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("SEGS"."SEGMENT_NAME"="OBJTS"."OBJECT_NAME")
filter("SEGS"."SEGMENT_NAME"="OBJTS"."OBJECT_NAME")
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
487 consistent gets
0 physical reads
0 redo size
248233 bytes sent via SQL*Net to client
2561 bytes received via SQL*Net from client
192 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
2851 rows processed
SQL> select/*+use_nl(segs,objts)*/*from segs, objts where segs.segment_name=objts.object_name;
2851 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 2045044449
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2450 | 528K| 4725 (1)| 00:00:57 |
| 1 | NESTED LOOPS | | | | | |
| 2 | NESTED LOOPS | | 2450 | 528K| 4725 (1)| 00:00:57 |
| 3 | TABLE ACCESS FULL | SEGS | 2355 | 287K| 14 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | IDX_OBJTS_NAME | 1 | | 1 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID| OBJTS | 1 | 96 | 2 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("SEGS"."SEGMENT_NAME"="OBJTS"."OBJECT_NAME")
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
3473 consistent gets
0 physical reads
0 redo size
227906 bytes sent via SQL*Net to client
2561 bytes received via SQL*Net from client
192 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2851 rows processed
三种连接方式,SQL数据量、语句相同,最后获取不同的成本消耗。可以看出,当数据量达到万级之后,Nest Loop Join的随机读会急剧增加,带来的CPU成本和总执行时间成本也会大大增加。
而使用Merge Sort Join带来的块读是相对较少,但是付出的CPU成本和执行时间也是不可忽视的。将数据集合排序映射到内存中(可能要利用Temp Tablespace),需要消耗很大的CPU和内存资源(排序段)。
总体来说,Hash Join在这个SQL中还是能带来很好的综合性能的。只有块读稍大,其他指标都是可以接受的最好值。
下面我们介绍与Hash Join相关的一些系统参数,和Hash Join进行的三种操作模式。不同的系统参数,可能会给CBO成本运算带来影响。不同的操作模式,帮助我们理解PGA中的hash_area大小是如何影响到Hash Join操作的性能。
3、Hash Join相关参数
Hash Join是CBO优化器才能生成的执行计划操作,如果是选择了RBO就不能生成包括Hash Join的执行计划。此外,与Hash Join相关的Oracle参数还包括下面几个:
ü Hash_Join_Enable
该参数是控制CBO启用Hash Join的开关。如果设置为True,则表示CBO可以使用Hash Join连接方式,否则就不可以使用。在目前的版本中,该参数已经演化为一个隐含参数,名称为“_hash_join_enable”。
SQL> col name for a20;
SQL> col value for a10;
SQL> col DESCRIB for a30;
SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ
2 FROM SYS.x$ksppi x, SYS.x$ksppcv y
3 WHERE x.inst_id = USERENV ('Instance')
4 AND y.inst_id = USERENV ('Instance')
5 AND x.indx = y.indx
6 AND x.ksppinm LIKE '%hash_join_enable%';
NAME VALUE DESCRIB
-------------------- ---------- ------------------------------
_hash_join_enabled TRUE enable/disable hash join
ü Hash_Area_Size
Hash Join操作是依赖独立的私有空间,我们称之为Hash_Area。Hash Area在Join过程中的作用就是将连接小表尽可能的缓存在Hash Area中,供进行Hash匹配和Bucket内部精确匹配。Hash Area是贮存在PGA中,属于会话session独立的一块空间。如果Hash Area较小,不足以存放小表全部数据,就会引起Temp表空间的使用,进而影响Hash Join性能。
4、连接三模式
Hash Join比较Merge Sort Join一个比较优势的地方,就是对PGA空间的有限使用上。但是,使用PGA毕竟是一种风险操作。因为Hash Area同Sort Area一样,在小表不能完全装入系统时,会调用Temp表空间的硬盘空间。这样,就会引起一些问题。
下面关于三种模式的阐述,借鉴八神前辈的《Oracle Hash Join》(http://www.alidba.net/index.php/archives/440)。特此表示感谢。
针对不同的状态,Oracle分别有不同的模式对应。
Optimal模式
这是我们进行Hash Join的最理想情况。驱动表(小表)生成的Hash数据集合可以完全存放在Hash Area的时候,我们称之为Optimal模式。
ü 首先找到驱动表,获取到驱动表。存放在Hash_Area中;
ü 在Hash Area中,对驱动表进行Hash操作,形成Hash Bulket,形成对应的分区信息。针对多个Bulket,同时形成一个Bitmap列表,做到Bulket与Bitmap位的联系;
ü 在各个Bulket中,分布着不同的数据行。如果连接列分布比较均匀,Bulket中数据也就比较均匀。如果Bulket中包括数据,对应该Bulket的Bitmap位上为1,否则为0;
ü 找被驱动表的每一列,将连接列值进行Hash处理。匹配Bitmap位,如果Bitmap为0,表示该列值没有存在,直接抛弃。否则进入Bulket进行精确匹配;
Onepass模式
如果我们设置的PGA空间小,或者连接的小表体积就已经很大了,那么就会利用到临时表空间。具体处理,就是进行两次的Hash处理,在Bulket层面的上面建立Partition分区。
当进行Hash操作的时候,出现的情形是一部分的Partition在内存中,另一部分Partition被存放在Temp表空间上。
在进行连接匹配的时候,如果能够在Bitmap中确定到Partition在内存中,那么直接在内存中进行检索和精确匹配过程。否则从Temp表空间中将对应的Partition调取到内存中,进行匹配操作。
Multipass模式
这是一种很极端的情况,如果Hash Area小到一个Partition都装不下。当进行Hash操作后,只有半个Partition能装入到Hash Area。
这种情况下,如果一个Partition匹配没有做到,还不能够放弃操作,要将剩下一半的Partition获取到进行Hash Join匹配。也就是一个Partition要经过两次的Bitmap匹配过程。
5、结论
Hash Join是一种效率很高,CBO时代很常见的连接方式。但是,相对于其他古典算法,Hash Join的综合效率很高,特别在海量数据时代。
Sort merge join、Nested loops、Hash join(三种连接类型)的更多相关文章
- Nested loops、Hash join、Sort merge join(三种连接类型原理、使用要点)
nested loop 嵌套循环(原理):oracle从较小结果集(驱动表.也可以被称为outer)中读取一行,然后和较大结果集(被侦查表,也可以叫做inner)中的所有数据逐条进行比较(也是等值连接 ...
- NESTED LOOPS & HASH JOIN & SORT MERGE JOIN
表连接方式及使用场合 NESTED LOOP 对于被连接的数据子集较小的情况,nested loop连接是个较好的选择.nested loop就是扫描一个表,每读到一条记录,就根据索引去另一个表里面查 ...
- oracle Hash Join及三种连接方式
在Oracle中,确定连接操作类型是执行计划生成的重要方面.各种连接操作类型代表着不同的连接操作算法,不同的连接操作类型也适应于不同的数据量和数据分布情况. 无论是Nest Loop Join(嵌套循 ...
- sql server 性能调优之 资源等待内存瓶颈的三种等待类型
一.概述 这篇介绍Stolen内存相关的主要三种等待类型以及对应的waittype编号,CMEMTHREAD(0x00B9),SOS_RESERVEDMEMBLOCKLIST(0x007B),RESO ...
- sql server 性能调优 资源等待之内存瓶颈的三种等待类型
原文:sql server 性能调优 资源等待之内存瓶颈的三种等待类型 一.概述 这篇介绍Stolen内存相关的主要三种等待类型以及对应的waittype编号,CMEMTHREAD(0x00B9),S ...
- mysql的三种连接方式
SQL的三种连接方式分为:左外连接.右外连接.内连接,专业术语分别为:LEFT JOIN.RIGHT JOING.INNER JOIN 内连接INNER JOIN:使用比较运算符来根据指定的连接的每个 ...
- linux学习之centos(二):虚拟网络三种连接方式和SecureCRT的使用
---操作环境--- 虚拟机版本:VMware Workstation_10.0.3 Linux系统版本:CentOS_6.5(64位) 物理机系统版本:win10 一.虚拟网络三种连接方式 当在V ...
- java Data、String、Long三种日期类型之间的相互转换
java Data.String.Long三种日期类型之间的相互转换 // date类型转换为String类型 // formatType格式为yyyy-MM-dd HH:mm:ss// ...
- SEO三种职位类型:编辑型SEO、技术型SEO、营销型SEO详解
SEO三种职位类型:编辑型SEO.技术型SEO.营销型SEO详解 网站SEO优化作为营销端的服务之一,这些年也呈现出日新月异的格局.一改过去游兵散将式的小作坊生产模式,不断有力量强大的公司团体加入到这 ...
随机推荐
- 移动混合开发之文件管理Final之总结
从昨天开始:2016年7月日,早晨用时1+2个小时左右,最开始还怀疑自己能否解决,但是最终还是自己解决, 所以下次遇到问题,最好还是尽量尝试自己解决. 1.css在设计的时候,一定要把父元素的长宽高指 ...
- Android 2016新技术
Android 2016新技术 版权声明:本文为博主原创文章,未经博主允许不得转载. 2016你需要了解Android有以下新兴的技术与框架,有些也许还不成熟,但是你应该去了解下,也许就是未来的方向. ...
- block的常见用法
一.声明和定义 1.声明 声明方式:返回值(^block)(参数).声明时,参数变量名可以省略:使用时,参数变量名不能省略,不然会无法调用传入的参数 void(^block)(); void(^blo ...
- APK签名是如何生成的
零.前言本文以支付宝手机客户端为例,进行剖析到支付宝官网下载当前最新版本:8.0.1 (2014-01-28)文件名为 alipay_wap_main.apkMD5 摘要为 69820edb3cd13 ...
- 《C++primer》v5 第5章 语句 读书笔记 习题答案
5.1 空语句只有一个";".如果什么也不想做可以使用空语句. 5.2 用花括号{}括起来的叫块,也叫复合语句.有多条语句作用在同一个作用域时,需要用花括号括起来. 5.3 降低了 ...
- 基于Bayes和KNN的newsgroup 18828文本分类器的Python实现
向@yangliuy大牛学习NLP,这篇博客是数据挖掘-基于贝叶斯算法及KNN算法的newsgroup18828文本分类器的JAVA实现(上)的Python实现.入门为主,没有太多自己的东西. 1. ...
- Frame动画实战
Android动画分为Tween动画和Frame动画,Tween动画主要包括图片的放大缩小.旋转.透明度变化.移动等等操作:Frame动画则简单得多了,就是把一张张的图片连续播放产生动画效果. 本节主 ...
- OD20
查壳 发现没有壳 那就载入OD 在命令中在API函数下下个断点 然后程序跑起来 , 点CHECK 断下来了 在动态链接库断下来了 我们alt+F9 回到用户界 ...
- redis DB操作
数据库操作 1) REDIS是全部由KEY和VALUE值构成,对数据库的增删改查操作都是基于在通过key 映射到哈希槽 然后通过哈希槽进行单向链式遍历 查找到value和具体的key. 同样 在查看 ...
- G - 非常可乐
Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Submit Status Pract ...