Oracle Parallel Execution解决的问题是:在shared-disk架构下,如何进行大查询。
整体思路是:存储上是共享的,内存中是MPP share-nothing的计算模型。
Oracle PX基于shared-disk做了2大优化:
- 动态扫描数据,解决数据倾斜问题;
- full partition-wise join,加速分区表join;
此外,Oracle是OLTP型数据库,没有按照AP性能最大化来设计PX,在优化器和执行器上和MPP系统都有比较大的不同:
- 优化器:Oracle PX的优化器是基于TP优化器的改进,优化器先按照非PX模式执行计划的探索,然后在此基础上插入DFO,数据分布等逻辑,而不是像GPORCA等为AP重新设计的cascade优化器;
- 执行器:2-DFO调度,非全流水线调度,节省PES进程资源,防止对TP造成太高的资源竞争;
下面是正文:
ABSTRACT
Oracle7基于shared-disk架构初步实现了并行执行,Oracle 10g重构了并行执行架构实现了全局并行计划树,更易于维护和对SQL特性的扩展,加速了Oracle的并行执行的演进。
1. Introduction and Overview
并行执行是处理大规模数据的关键技术。一个先进的执行引擎能够支持节点的弹性扩展,动态的申请和释放。
Oracle 10g是基于shared-disk,每个节点可以访问所有的数据,数据无需事先分区。
通过优化器产生高性能的并行计划树以及Parallel Execution执行期优化(简称PX)能够把负载打散在几个节点上,同时降低节点间网络开销。对关键资源比如内存以及锁等通过execution-constructs做约束。
Oracle 10g的PX引入了PSC机制(Parallel Single Cursor),各个执行节点共享同一份计划树。解决了之前使用Oracle PX时的手工运维管理,手工监控,手工性能诊断等问题。
2. Concepts and key abstractions
Oracle PX支持两种并行机制:intra和inter。
1. intra:同一个节点,通过共享内存通信;
2. inter:跨节点,通过网络通信;
由PEC(Parallel Execution Coordinator)和PES(Parallel Execution Server)组成。
Oracle PX支持所有SQL功能:
1. relation操作符;
2. DML,DDL,分区表;
3. bulk load(外表);
4. AP类SQL;
5. data mining;
PEP(parallel execution plan)由4部分组成:
1. Dataflow operators(DFOs),由多个row source组成,类似slice,fragment的概念;
2. Table Queues(TQs),类似motion,shuffle,Exchange的概念;
3. GRA(granule interators控制水平动态切分表),shared-disk架构特有的功能,一个woker可以从其他worker上steal任务;
4. Parallelizer row source(控制并行度);
3. Parallel Single Cursor Model
在PSC(Parallel Single Cursor)模型中,使用单个全局的plan树表达并行执行所需的所有信息。计划树由PEC生成,PEC和PES同时调度执行该计划树。
3.1 Generation of a Single PEP
先生成逻辑计划树,然后再生成物理计划树
3.1.1 逻辑优化
- first pass
考虑join顺序;
考虑access nethod;
考虑开启并行的代价:节点数,每个对象的分区数,分布方式; - second pass:
计算最优的distribution算法,使得plan被parallel化;
3.1.2 物理优化:
把1中的逻辑计划中,相关的算子(row source)组织成DFO,考虑clustering,排序属性,data-frag特性;
这个阶段不会考虑DOP(应该启动多少个并行度),优化器对并行的感知和share-nothing的引擎如:DB2-PE,Teradata类似。
和MPP的火山全流水模型不同的是,Oracle的并行的进程数目是固定的:2倍的DOP。
所有PES进程分成2个集合,每个集合下面有DOP个PES进程。执行时一个集合做为生产者,一个集合做为消费者;
生产者执行完当前DFO算子之后,切换成消费者;
原来的消费者,变成了生产者;
3.2 Implication of a Single Global PEP
由于并行需要在多个PES进程之间共享DFO计划,在经过物理优化之后得到一个可执行的计划树后,大多数DB的并行执行引擎,会使用中间语言或者更高级别的SQL结构来表达DFO树(序列化和反序列化),Oracle在实践中发现随着执行引擎不断的迭代和增大,中间语言和SQL表达DFO的逻辑维护异常复杂,需要时刻维护SQL和plan的序列化和反序列化相关逻辑和组件的一致性:
1. 中间语言:每个DFO用中间语言表达和执行过程极易出错(一旦出错,整个大查询终止);
2. 使用SQL描述DFO:先生成计划树,再把一个个DFO翻译成SQL,DFO是物理执行层面的树,SQL是声明式语言,无法建立一一对应的关系;
Oracle的并行执行引擎的做法是:
1. QC分发原始的SQL给PES进程组;
2. 每个节点上的一个PES进程再执行一次优化器生成plan;
3. 该节点上其他PES进程直接使用生成的plan;
好处:
1. 提升并行查询期间的管理和监控:所有的并行相关结构在物理计划中也被抽象成了算子(row source);每个算子的统计(内存,消息数,负载倾斜)等可以记录在算子上,最后可以把所有PES进程上的所有算子做聚合,得到计划树在多个节点上的执行情况;
2. 支持新的px算子时,无需修改序列化和反序列化相关的兼容问题,只要定义新算子的相关属性即可(类似单机算子);
3. 代码可维护性,方便调试,同时减少中间plan树的内存;
4. Execution of a Parallel Single Cursor
- PEC和PES共享相同的plan;
- PEC先给PES发送调度DFO的控制信息(启动PES进程组);
- PES扫描一个fragment info,通过GRA算子实现,每次消耗完一个granule就向PEC请求下一个granule(比如:一个granule代表一批block),生产的数据往对端PES消费者进程组发送,只有消费进程组消费完了后,才请求后续的granule。通过这种方式实现了动态的负载均衡;
在shared-nothing的系统中,每个表都必须使用分区存储,因此每个节点只能访问一个分区的数据(Teradata和GP默认是Hash的方式)。
调度器必须感知数据分区和节点的静态的映射关系,一个分区上的数据不能被其他节点访问。
Oracle PX不要求数据一定是分区存储的,Oracle的分区表只是用来高可用和性能,Oracle的PX引擎不受用户如何分区的限制(实际上分区的使用应该仅仅考虑业务上的特性,而不需要和性能绑定)。
Oracle的PX同样会对分区做优化:Full Partition-wise join,每个PES进程只扫描2个表的特定的分区数据直接join,而不用和其他PES进程之间交互数据。而且任何一个PES都可进行partition-wise join,因此底层是共享存储。
4.1 Cluster-aware PX
4.1.1 partition-wise join
在优化器阶段,考虑能启动的PES数目,以及query中扫描到的分区数目,尽量的在数据的流动的垂直方向进行切分,以减少横向的数据流动。
2个表分别有4个分区表,为了减少数据的横向流动使用partition-wise join。每个节点处理2个成对的分区表。
partition-wise join时,一个PES进程只处理一个分区表,最大的并行度是有限制的,比如上图中,DOP不能超过4。
也许使用更多的DOP能提高整体性能,多个DOP同时扫描一个分区表,这样就需要横向的数据流动了,因此,最终应该通过优化器来决定DOP的数目。
和shared-nothing的系统又本质的区别,shared-nothing的并行度是固定的,一个进程只处理一个分区表。
4.1.2 px hash join
下图是DOP=8,一共16个PES进程的执行过程。8个生产者8个消费者,生产者在发送数据时需要根据join key进行hash(这个过程叫重分布),几个PES生产进程共同扫表一个分区表。
4.1.1 hybrid partition-wise join
在partition-wise中,如果分区数目比较少,那么就无法启动更多的DOP来计算。
hybrid的模式:把PES进程根据分区表的数目进行分组。多个PES进程处理partition-wise join中的一对分区表。1个分区表的多个PES进程之间需要shuffler(如果在一台机器上,无需网络及,直接sharememory),而分区表之间的PES进程组不需要;
好处是:无需all node data tansform,尤其是有大量的小节点;
hybrid模式:
1. 可以看做是, partition-wise join执行模式的扩展,partition-wise join中一个PES进程处理一个分区,现在是多个PES进程处理一个分区;
2. 也可以看做是,对普通PX执行的约束,PES之间增加一个映射关系,使得集合内部是普通的PX执行;
hybrid模式通过PES-mapper机制来实现:
1. 根据物理约束(分区表),把pes分成组,组之间无联系,组内在一台机器上,通过共享内存通信;
2. 优化器提供一个PES mapper函数,每行数据经过PES mapper之后找到相应的组内的消费者PES进程;
PES-mapper优化:表现如同share-nothing,同时可以利用shareddisk来负载均衡;
PES Mapper方式类似MPP中:一个分区启动多个worker。
4.2 PM Performace
PES mapper机制提升30%,pm机制保证节点间没有数据流动,可以方便的扩展节点数。
4.3 Resource-Aware PX
PX是资源消耗性查询,不能影响正常的TP查询,因此PX需要做严格的资源管理:
1. 内存:统计每个节点内存情况,动态分配DOP,比如:对分区表执行parallel INSERT,可以每个PES进程处理一个分区,但是如果分区特别多,PES就会很多,内存占用就会很大,PES mapper把一个PES处理多个独立的分区表;;
2. 锁:parallel DELETE/UPDATE在并行执行时会对同一个block上锁,PES mapper机制限制每个object被上锁的次数,控制PES数目;
3. 自适应DOP和PES分配:
1. 先确定参与px的节点:计算节点按照业务编号,支持只在固定node上服务固定业务的sql,
2. 确定inter和intra;
4. granule:分配unit时,考虑data locality和affinity;也可以根据SQL特点,分配unit;
5. A feature-rich Parallel Engine
5.1 Flexible data distribution and pipeline
如果多个表join后的结果集进行group-by和order-by,那么优化器会考虑把hash重分布替换成range分布模式(Oracle独有的技术),同时消除底层DFO的order-by;
ETL场景,对table function的输入使用px扫描:
1. 多PES进程扫描一个分区;
2. 扫描时外部数据进行granule切分(动态平衡);
3. 再按照partition by传给对应执行function的PES进程组;
4. 如果输入的hash和导入新表的partition by的hash是一致的,无需数据重分布;
5.2 Cost-based Parallelization of Subqueries
Oracle支持大部分子查询转join和agg的逻辑优化技术。
对于实在不能去关联化的子查询,可以对子查询部分独立的启动并行度PX或者串行执行,这取决于启动px的代价;
5.3 Recursive and Interative Computation
通过DFO之间传输中间结果集的temp table,以支持px+递归;
5.4 Load-Balanced Table Queues
对数据分布敏感的分布策略,进行动态的sampling,防止range倾斜;
6. Conclusions
本文讲解了Oracle10g的并行执行引擎技术:
1. Oracle10g对OPS进行了重构,替代了原来使用DSL对plan进行序列化和反序列化,PEC和PES节点之间传输SQL,每个节点独自执行优化得到single-plan,每个节点上不同PES共享一份single-plan;
2. 执行模型和数据分布解耦合。底层数据是shared-disk存储,而不是share-nothing系统中的分片存储。PX可以在任意节点扫描任意数据集合,因此PES-mapping机制可以更加灵活的在PES进程和节点上进行重新安排,充分的考虑集群内存,锁,网络等因素;
3. Oracle10g借助PX框架对大量的SQL场景进行了并行优化;