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优化作为营销端的服务之一,这些年也呈现出日新月异的格局.一改过去游兵散将式的小作坊生产模式,不断有力量强大的公司团体加入到这 ...
随机推荐
- 滑动的scrollowview的导航渐变
CGFloat offsetY = scrollView.contentOffset.y; CGFloat alpha = 0; if (offsetY >= 64) { alpha=((off ...
- 第三篇——软件之殇,WE ARE THOUSANDS APART!
软件工程是一门工程性的学科,其目标主要是成功地建造一个大型软件系统.这其中包括:付出较低的开发成本:达到要求的软件功能:取得较好的软件性能:开发的软件易于移植:需要较低的维护费用:能按时完成开发任务, ...
- 自定义iOS7导航栏背景,标题和返回按钮文字颜色
在iOS7下,默认导航栏背景,颜色是这样的,接下来我们就进行自定义,如果你仅仅是更改一下背景和颜色,代码会很简单,不需要很复杂的自定义View来替代leftBarItem 更改导航栏的背景和文字Col ...
- cocos2dx-3.9 集成admob
Part 1: 安装GoogleMobileAds framework (即admob) 1. 安装Cocoapods,否则解决依赖关系和配置真的会把人不累死也得烦死 sudo gem install ...
- BackgroundWorker组件的作用
当构建一个图形化的Windows Form桌面应用程序并且需要执行在应用程序主UI线程之外的线程中长时间的任务时,BackgroundWorker类就很有用了. 要使用BackgroundWorker ...
- hadoop2的高可用性
1 hadoop2 namenode由一个节点变成两个节点,同时在线,且同时只有一个是活跃的,如果一个出了问题,另外一个立即接替:没必要配置Secondary NameNode.Checkpoi ...
- [解决方案] pythonchallenge level 3
http://www.pythonchallenge.com/pc/def/equality.html 根据页面提示:一个小写字母刚刚好被左右3个大写字母包围. 查看页面代码得到需要处理的字符. 将字 ...
- javaweb常见问题解决
问题一.如果是在导入的项目的情况下,多数情况下就是jdk版本与项目的jdk版本不匹配, 解决方法: (1)右击工程->Build Path->Configure Build Path-&g ...
- Java常用的输入输出方法
对于经常上机刷题的来说,首先得解决输入输出方法,Java的输入输出流在Java学习过程的后面部分才会接触,但是我们可以掌握一些简单的,常用的输入输出方法 首先输出 大家最熟悉的莫过于输出方法,直接用S ...
- [转]PYTHON-SCRAPY-WINDOWS下的安装笔记
分类: Crawler.Net Python2014-05-15 13:36 127人阅读 评论(0) 收藏 举报 PYTHON SCRAPY 1.安装PYTHON2.7.6,下载地址:https:/ ...