您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
   
 
 
     
   
 订阅
  捐助
陈焕生:深入理解Oracle 的并行执行(四)
 
作者 陈焕生 火龙果软件  发布于 2015-3-5
  2854  次浏览      33
 

HASH JOIN BUFFERED,连续hash分发时执行计划中的阻塞点

到目前为止,所有的测试只涉及两个表的连接。如果多于两个表,就需要至少两次的hash join,数据分发次数变多,生产者消费者的角色可能互换,执行计划将不可避免变得复杂。执行路径变长,为了保证并行执行的正常进行,执行计划可能会插入相应的阻塞点,在hash join时,把符合join条件的数据缓存到临时表,暂停数据继续分发。本节我使用一个三表连接的sql来说明连续hash join时,不同分发方式的不同行为。

使用Broadcast分发,没有阻塞点。

测试三个表连接的sql如下,加入part表,使用hint让优化器两次hash join都使用broadcast分发。Replicate SQL查询性能类似。

SQL执行时间为42秒,dbtime为2.6分钟。

AAS=(sql db time)/(sql 执行时间)=(2.6*60)/42=3.7,接近4,说明4个PX进程基本一直保持活跃。

执行计划是一颗完美的右深树,这是星型模型查询时执行计划的典型形式。生产者对两个维度进行broadcast分发,消费者接受数据之后准备好两次hash join的build table, 最后扫描事实表,并进行hash join。我们通过跟随table queue顺序的原则,阅读这个执行计划。

  1. 红色PX进程作为生产者并行扫描part,通过tablequeue0广播给每个蓝色的消费者PX进程 (第7~9行)。每个蓝色的PX进程接收part的完整数据(第6行),1.2M行记录,并准备好第5行hash join的build table。
  2. 红色PX进程作为生产者并行扫描customer,通过tablequeue1广播broadcast给每个蓝色的 消费者PX进程(第12~14行)。每个蓝色的PX进程接收customer的完整数据(第11行),1.5M行记录,并准备好第10行hash join的build table。
  3. 蓝色的PX进程并行扫描事实表lineorder,对每条符合扫描条件(如果sql语句包含对lineorder的过滤条件)的3亿行记录,进行第10行的hash join,对于每一条通过第10行的 hash join的记录,马上进行第5行的hash join,接着再进行聚合。从sql monitor报告的 Timeline列信息,对lineorder的扫描和两个hash join操作是同时进行的。执行计划中没有阻塞点,数据在执行路径上的流动不需要停下来等待。大部分的db cpu消耗在两次hash join操作。最优化的执行计划,意味着经过每个hash join的数据越少越好。对于这类执行计划,你需要确保优化器把最能过滤数据的join,放在最接近事实表的位置执行。

连续hash分发,执行计划出现阻塞点

使用以下hints,强制SQL使用hash分发。 

SQL执行时间为1.5分钟,dbtime为8.1分钟。相对于增加了14GB的IO操作。 

连续两次hash join都使用HASH分发,每次hash join左右两边都需要分发,PX进程之间发生4次数据分发。执行计划中最显著的地方来自第12行的HASH JOIN BUFFERED,这是一个阻塞性的操作。下面,我们依然通过跟随table queue顺序的原则,阅读执行计划,并解析为什么出现HASH JOIN BUFFERED这个阻塞操作,而不是一般的HASH JOIN。

1. 蓝色的PX进程作为生产者,并行扫描customer,通过tablequeue0,hash分发给作为消费者的红色PX进程(第14~16行)。每个红色的PX进程接收了1/4的customer的数据(第13行), 大约为370k行记录,并准备好第12行‘HASH JOIN BUFFERED’的build table。与broadcast分发区别的是,此时执行计划是从第16行,扫描靠近lineorder的customer开始的,而不是从第一个没有’孩子’的操作(第9行扫描part)开始的。这是hash分发和串行执行计划以及broadcast分发不同的地方。

2. 蓝色的PX进程作为生产者,并行扫描lineorder,通过tablequeue1,hash分发作为消费者的红色PX进程(第18~20行)。每个红色PX进程接收了1/4的lineorder数据(第17行),大约75M行记录。每个红色PX进程在接收通过tablequeue1接收数据的同时,进行第12行的hash join,并把join的结果集在PGA中作缓存,使数据暂时不要继续往上流动。如果结果集过 大的话,需要把数据暂存到临时空间,比如我们这个例子,用了7GB的临时空间。你可以理解为把join的结果集暂存到一个临时表。那么,为什么执行计划需要在这里插入一个阻塞点,阻止数据继续往上流动呢?

这里涉及生产者消费者模型的核心:同一棵DFO树中,最多只能有两组PX进程,一个数据分发要求两组PX进程协同工作; 这意味着同一时刻,两组PX进程之间,最多只能存在一个活跃的数据分发,一组作为生产者发送数据,一组作为消费者接收数据,每个PX进程只能扮演其中一种角色,不能同时扮演两种角色。当红色的PX进程通过tablequeue1向蓝色的PX进程分发lineorder数据,同时,蓝色的PX进程正在接收lineorder数据,并进行hash join。观察timeline列的时间轴信息,第12,17~20行是同时进行的。 但是此时红色的PX进程不能反过来作为生产者,把hash join的结果分发给蓝色进程,因为此时有两个限制:

• 蓝色的PX进程作为生产者,正忙着扫描lineorder;此时,无法反过来作为消费者,接收来自红色PX进程的数据。

• 第5行hash jon操作的build table还没准备好,这时表part甚至还没被扫描。

所以Oracle需要在第12行hash join这个位置插入一个阻塞点,变成HASH JOIN BUFFER操作,把join的结果集缓存起来。当蓝色的PX进程完成对lineorder的扫描和分发,红色的PX进程完成第12行的hash join并把结果完全暂存到临时空间之后。Tablequeue2的数据分发就开始了。

3. 红色的PX进程作为生产者, 并行扫描part,通过tablequeue2,分发给作为消费者的蓝色PX进程(第7~9行)。每个蓝色PX进程接收了1/4的part数据(第6行),大概300k行记录,并准备好第5行hash join的build table。

4. 红色的PX进程作为生产者,把在第12行”HASH JOIN BUFFERED”操作,存在临时空间的对于customer和lineorder连接的结果集,读出来,通过table queue 3,分发给蓝色的PX进程(第11~12行)。“HASH JOIN BUFFERED”这个操作使用了7GB的临时空间,写IO7GB,读IO 7GB,IO总量为 14GB。

5. 每个蓝色的PX进程作为消费者,接收了大约75M行记录。对于通过tablequeue3接收到的 数据,同时进行第5行的hash join,并且通过join操作的数据进行第4行的聚合操作。当tablequeue3上的数据分发结束,每个蓝色的PX进程完成hash join和聚合操作之后,再把各自的聚合结果,一行记录,通过tablequeue4,分发给QC(第3~5行)。QC完成最后的聚合,返回给客户端。

小结

因为使用星型模型测试,这个例子使用Broadcast分发或者replicate才是合理的。实际应用中,连续的hash分发并不一定会出现HASH JOIN BUFFERED这个阻塞点,如果查询涉及的表都较小,一般不会出现HASH JON BUFFERED。即使执行计划中出现BUFFER SORT,HASH JOIN BUFFERED等阻塞操作,也不意味着执行计划不是最优的。如果sql性能不理想,HASH JOIN BUFFERED操作消耗了大部分的CPU和大量临时空间,通过sql monitor报告,你可以判断这是否是合理的:

  1. 检查estimated rows和actual rows这两列,确定优化器对hash Join左右两边cardinality估算是否出现偏差,所以选择hash分发。
  2. 同样检查hash join操作的estimated rows和actual rows这两列,优化器对hash join结果集cardinality的估算是否合理。优化器会把hash join的两边视为独立事件,对join结果集cardinality的估算可能过于保守,estimate rows偏小。对于星型模型的一种典型情况:如果多个维度表参与连接,执行路径很长,一开始维度表的分发方式为broadcast,事实表不用分发,经过几次join之后,结果集cardinality下降很快,后续hash join两边的estimated rows接近,导致优化器选择hash分发。
  3. 通过检查每个join所过滤的数据比例,确定优化器是否把最有效过滤数据的join最先执行,保证在执行路径上流动的数据量最少。

Hash join和布隆过滤

布隆过滤在并行执行计划中的使用非常普遍,我将在本章节解释这一数据结构及其作用。 从11.2版本开始,串行执行的sql也可以使用布隆过滤。

关于布隆过滤

布隆过滤是一种内存数据结构,用于判断某个元素是否属于一个集合。布隆过滤的工作原理图2如下:

引用自维基百科:http://en.wikipedia.org/wiki/Bloom_filter

如图,布隆过滤是一个简单的bit数组,需要定义两个变量:

  1. m:数组的大小,这个例子中,m=18.

  2. k:hash函数的个数,这个例子中,k=3,

一个空的布隆过滤所有bit都为0。增加一个元素时,该元素需要经过三个hash函数计算, 得到3个hash值,把数组中这三个位置都置为1。集合{x,y,z}的3个元素,分布通过三次hash计算,把数组9个位置设置为1。判断某个元素是否属于一个集合,比如图中的w, 只需对w进行三次hash计算产生三个值,右边的位置在数组中不命中,该位置为0,可以确定,w不在{x,y,z}这个集合。由于存在hash碰撞,布隆过滤的判断会过于乐观(false positive),可能存在元素不属于{x,y,z},但是通过hash计算之后三个位置都命中,被错误认定为属于{x,y,z}。根据集合元素的个数,合理的设置数组大小m,可以把错误判断的几率控制在很小的范围之内。

布隆过滤对hash join性能的改进 

布隆过滤的优势在于使用的很少内存,就可以过滤大部分的数据。如果hash join的左边包含过滤条件,优化器可能选择对hash join左边的数据集生成布隆过滤,在扫描hash join右边时使用这个布隆布隆作为过滤条件,第一时间把绝大部分不满足join条件数据排除。减少数据分发和join操作所处理的数据量,提高性能。

使用布隆过滤时的性能

使用布隆过滤时的性能对customer使用c_nation=’CHINA’条件,只计算来自中国地区的客户订单的利润总和。我们观察使用布隆过滤和不使用布隆过滤时性能的差别。

SQL执行时间为1秒,dbtime为7.9 秒。优化器默认选择replicate的方式。执行计划中多了JOIN FILTER CREATE和JOIN FILTER USE这两个操作。SQL的执行顺序为每个PX进程重复扫描customer表(第7行),对符合c_nation=’CHINA’数据集,60K(240K/4)行记录,在c_custkey列生成布隆过滤:BF0000(第6行JOIN FILTER CREATE)。在扫描lineorder时使用这个布隆过滤(第8行JOIN FILTER USE)。虽然lineorder总行数为300M,sql没有过滤条件,只使用布隆过滤,扫描之后只返回28M行记录,其他272M行记录被过滤掉了。每个PX进程在hash join操作时,只需处理60K行customer记录和7M(28M/4)行lineorder记录的连接,大大降低join操作的成本。对于Exadata,Smart Scan支持布隆过滤卸载到存储节点,存储节点扫描lineorder时,使用布隆过滤排除272M行记录,对于符合条件的数据,把不需要的列也去掉。Cell offload Efficiency=98%,意味着只有30GB的2%从存储节点返回给PX进程。如果不使用布隆过滤,Cell Offload Efficieny不会高达98%,我们将在下个例子看到。对于非Exadata平台,由于没有Smart Scan特性,数据的过滤操作需要由PX进程完成,布隆过滤的效果不会这么明显。12C的新特性Database In-­‐memory,支持扫描列式存储的内存数据时,使用布隆过滤。 

执行计划中出现第10行对LINEORDER的扫描时,使用了布隆过滤条件:SYS_OP_BLOOM_FILTER(:BF0000,"LO_CUSTKEY")

不使用布隆过滤时的性能

接着,我们通过hint NO_PX_JOIN_FILTER,禁用布隆过滤,观察此时的sql执行性能。

SQL执行时间为9秒,dbtime为33.7秒。比使用布隆过滤时,性能下降明显。优化器依然选择replicate的方式,执行计划中没有PX JOIN CREATE和PX JOIN USE操作。db time增加为原来4倍的原因: 

  1. 当PX扫描lineorder时,返回300M行记录。没有布隆过滤作为条件,每个PX进程需要从存储节点接收75M行记录。
  2. 进行第5行的hash join操作时,每个PX进程需要连接60k行customer记录和75M行lineorder记录。Join操作的成本大幅增加。

由于没有布隆过滤,Cell Offload Efficiency下降为83%。

HASH分发时布隆过滤的生成,传输,合并与使用

我们通过hint强制使用hash分发,观察此时sql执行计划中布隆过滤的生成和使用。

此时sql执行时间为4秒,db time为19.4秒。执行计划第6行为JOIN FILTER CREATE; 第13行为JOIN FILTER USE。此例,PX 进程分布在多个RAC两个实例,Hash分发时涉及布隆过滤的生成,传输,合并和使用,较为复杂,具体过程如下: 

  1. 布隆过滤的产生:4个蓝色的PX进程作为消费者,通过tablequeue0,接收红色的PX进程hash分发的customer数据,每个蓝色的PX进程接收15K行记录。接收customer记录的同时,实例1的两个蓝色PX进程在SGA共同生成一个布隆过滤,假设为B1; 实例2的两个蓝色PX进程在SGA共同生成一个布隆过滤,假设为B2。因为位于SGA中,布隆过滤B1对于实例1的 两个红色的PX进程是可见的,同样,B2对于实例2的两个红色PX进程也是可见的。
  2. 布隆过滤的传输:当红色的PX进程完成对hash join左边customer的扫描,就会触发布隆过滤B1/B2的传输。实例1的红色PX进程把B1发给实例2的蓝色PX进程; 实例2的红色PX进程把B2发给实例1的蓝色PX进程。
  3. 布隆过滤的合并:实例1的蓝色PX进程合并B1和接收到的B2; 实例2的蓝色PX进程合并B2和接收到的B1。合并之后,实例1和2产生相同布隆过滤。
  4. 布隆过滤的使用:实例1和2的4个红色的PX进程作为生产者,并行扫描lineorder时使用 合并之后的布隆过滤进行过滤。Lineorder过滤之后为49M行记录,此时的布隆过滤似乎没有replicate时的有效。Cell Offloadload Efficiency为97%。

如果并行执行只在一个实例,则红色的PX进程不需要对布隆过滤进行传输,蓝色的PX进程也无需对布隆过滤进行合并。

因为hash join的成本大大降低了,对于lineorder 49M行记录的hash分发,成为明显的平均,占53%的db time。

小结

本节阐述了布隆过滤的原理,以及在Oracle中的一个典型应用:对hash join性能的提升。布隆过滤的本质在于把hash join的连接操作提前了,对hash join右边扫描时,就第一时间把不符合join条件的大部分数据过滤掉。大大降低后续数据分发和hash join操作的成本。不同的分布方式,布隆过滤的生成和使用略有不同:

  • 对于broadcast分发和replicate,每个PX进程持有hash join左边的完整数据,对连接键生成一个完整的布隆过滤,扫描hash join右边时使用。如果sql涉及多个维度表,维度表全部使用broadcast分发,优化器可能对不同的维度表数据生成多个的布隆过滤,在扫描事实表时同时使用。
  • 对于hash分发,作为消费者的PX进程接收了hash join左边的数据之后,每个PX进程分别对各自的数据集生成布隆过滤,再广播给作为生产者的每个PX进程,在扫描hash join右边时使用。

真实世界中,优化器会根据统计信息和sql的过滤条件自动选择布隆过滤。通常使用布隆过滤使都会带来性能的提升。某些极端的情况,使用布隆过滤反而造成性能下降,两个场景:

  • 当hash join左边的数据集过大,比如几百万行,而且连接键上的唯一值很多,优化器依然选择使用布隆过滤。生成的布隆过滤过大,无法在CPU cache中完整缓存。那么使用布隆过滤时,对于hash join右边的每一行记录,都需要到内存读取布隆过滤做判断,导致性能问题。
  • 如果Join操作本身无法过滤数据,使用布隆过滤时hash join右边的数据都会命中。优化器可能无法意识到join操作无法过滤数据,依然选择使用布隆布隆。如果hash join右边数据集很大,布隆过滤可能会消耗明显的额外cpu。
   
2854 次浏览       33
相关文章

基于EA的数据库建模
数据流建模(EA指南)
“数据湖”:概念、特征、架构与案例
在线商城数据库系统设计 思路+效果
 
相关文档

Greenplum数据库基础培训
MySQL5.1性能优化方案
某电商数据中台架构实践
MySQL高扩展架构设计
相关课程

数据治理、数据架构及数据标准
MongoDB实战课程
并发、大容量、高性能数据库设计与优化
PostgreSQL数据库实战培训
最新活动计划
嵌入式软件架构设计 12-11[北京]
LLM大模型与智能体开发实战 12-18[北京]
嵌入式软件测试 12-25[北京]
AI原生应用的微服务架构 1-9[北京]
AI大模型编写高质量代码 1-14[北京]
需求分析与管理 1-22[北京]

MySQL索引背后的数据结构
MySQL性能调优与架构设计
SQL Server数据库备份与恢复
让数据库飞起来 10大DB2优化
oracle的临时表空间写满磁盘
数据库的跨平台设计
更多...   


并发、大容量、高性能数据库
高级数据库架构设计师
Hadoop原理与实践
Oracle 数据仓库
数据仓库和数据挖掘
Oracle数据库开发与管理


GE 区块链技术与实现培训
航天科工某子公司 Nodejs高级应用开发
中盛益华 卓越管理者必须具备的五项能力
某信息技术公司 Python培训
某博彩IT系统厂商 易用性测试与评估
中国邮储银行 测试成熟度模型集成(TMMI)
中物院 产品经理与产品管理
更多...