Original
2016-04-08
星环科技
星环科技
你可能要问小编:你为啥心情这么好啊?! 哈哈,你觉得呢?因为,明天又是周末啦!Lalala~小编猜~你们现在的内心肯定充满了淡淡的忧伤~莫忧伤,虽然小编周末不能陪你们,但是小编今天给你们Share的技术干货,绝对够你享用这个周末啦! 今天这篇是自称为 “ 星环科技美男子 " 战五孙先生的演讲稿。我们的美男子在2016Hadoop技术峰会上的大数据优化技术专题论坛,跟大家分享了星环科技在大数据平台上对PL/SQL存储过程的并行编译优化经验。
话不多说,好东西接好!
PL/SQL是对SQL语言的一种过程化的扩展,全名就是Procedure Language SQL。PL/SQL产生后,在各行业,特别金融、运营商的业务中有广泛应用。它具有如下几个优点:
1. PL/SQL是直接基于SQL扩展,故而与SQL耦合紧密,用户可以直接在PL/SQL程序中写SQL语句,非常便利。2. 提供了丰富的语法,能够支持复杂业务逻辑的表达。3. 完整的事务处理能力,PL/SQL同时支持嵌套事务和自制事务。后者是普通的客户端服务器形式下无法做到的。4. 原生的异常处理:在描述业务逻辑的时候直接嵌入异常处理,及时发现异常并做记录。5. 和服务端客户端模式相比,一条PL/SQL只需要一次性通信,减少了客户端并发压力。
由于PL/SQL是基于SQL进行的拓展,存储过程只是提供过程化扩展,其终极目标是SQL语句的顺利执行。PL/SQL为数据从DB空间到PL/SQL提供了一个串行处理的桥梁。它有如下几种交互方式:
1. 程序中直接写SQL语句。如下图所示的代码范例,它有一个本地变量var,并直接在执行块中写SQL语句。请注意,这个变量的值可以作为该SQL语句中表达式的标识符,故而 SQL的含义是随着这个变量的值变化而变化,这意味着SQL和PL/SQL的上下文是一体的,为用户提供了极大的便利。我们可以有两种形式,一种是直接使用,另一种是动态的形式EXECUTE IMMEDIATE,通过问号来改变VAR。
2. 通过显式游标对结果集进行迭。通过关键字cursor定义游标,如下图范例所示。首先把表里所有记录选出来,并定义一个本地变量去接一下游标的结果。然后打开游标,并通过循环语句来迭代游标的结果集,通过将游标内容fetch到本地变量中,实现数据从DB空间到PL/SQL空间的转换。循环语句的退出条件是游标的属性NOTFOUND,表示再没有数据了。
3. 隐式游标。隐式游标和显式游标类似,通常出现在FOR循环开始,这样游标内容会直接参与变量迭代,并能够直接运算。它的优点在于不需要OPEN或者FETCH,使用便捷。
4. SELECT INTO。SELECT INTO通常用于取出聚合值,适用于实时算出一个结果的场景。以上就是PL/SQL调用SQL的几种方式,但是在大数据场景下,串行效率会遇到性能瓶颈。如下图范例,通过一个隐式游标把这个结果迭代一遍。一般来说,这样的依次迭代只能在一台机器上,通过程序本身的语义来保证串行执行的结果。这就导致了性能的瓶颈。
在探讨优化之前,我们还要了解一下我们产品对PL/SQL解释执行的过程。
1. 编译过程首先要经过一个编译的过程。用户程序是一段文本,如下图左边所示,这样一段程序的文本,经过初级编译,通过词法分析和语法分析,生成了一个对程序文本最初级的描述,叫AST(抽象语法树),如右图所示。
得到AST后就可以进行语义分析,主要包括分析所引用的变量是否存在、函数是否存在等。语义分析出来的内容和AST长类似,如下图所示。它是编译器中的一个中间表示,我们称之为执行块。执行块的根节点依然是BEGIN/END,随后两个子执行块分别是赋值和函数调用,现在已经识别出函数调用,所以标识符已经解析出来是PUT_LINE并记录到函数调用执行块内部。赋值语句的左侧识别出对变量var的引用,所以执行块为引用执行块,即REF,右侧是一个文字常量“Hello world”,执行块为LATERAL。再下面是函数调用的实参,依然是对var的引用,所以执行块仍旧为REF。有了这个中间表示后,编译器会进行后端处理,生成目标代码,并进行优化,这部分不在今天的讨论范围。
2. SQL语句的执行编译之后进入了PL/SQL执行的过程。我们所采用的架构是PL/SQL和SQL分别为两个独立的引擎。具体的做法是,一个PL/SQL文本进来,PL/SQL引擎会对每一条语句做一个大概的判断,如果是一条非SQL语句,会交给过程语句执行引擎去执行,如果是SQL语句,会送交给SQL引擎去执行,必要的话会把SQL的结果捞回来。这就是PL/SQL当中SQL语句执行的架构。
在探讨优化之前我们需要先分析一下PL/SQL的性能瓶颈在什么地方。我们观察到,普通的控制流不会遇到性能的瓶颈,因为普通的控制流不会去对大数据量进行迭代操作。直接的SQL,也不需要对结果进行叠代,它是天然并行的,因为我们的SQL引擎就是并行的。剩下的就是游标,绝大多数性能瓶颈都是游标引起的,因为它把并行语义变成了串行语义,是一种编程模式上的并行转串行。那么我们看一下游标中存在哪些优化的机会。在我们客户实际部署的项目中我们观察到:对游标迭代通常为单层循环;循环体内部控制流逻辑通常较简单;较少的全局变量写操作,这是很关键的;循环体内存在若干条SQL语句,某种程度上加大了优化的难度。下面这段代码,是一个典型的客户案例。 从这段代码中我们可以看到,这是一个隐式的游标。提出的优化策略有两类,一个是宏观层面,一个是微观层面,两者粒度不同。宏观层面的并行优化会适当重构客户的业务逻辑,通过对原表做自顶向下的切分,并各自进行PL/SQL函数,落到目标表。这种优化策略有其优缺点。优点是并行逻辑直观,效率提升明显,它的并行度基本上等于SQL引擎对原表进行拆分的粒度。能够支持较复杂的控制流。缺点在于需要对宏观层面的业务逻辑进行重新审视,要求业务逻辑满足特定条件,在有些场景下业务逻辑改动较大。接下来讨论微观层面优化策略,这主要是对程序的局部热点做并行化,大部分工作由编译器来自动完成的。它的主要思想可以由下面边这张图来解释:
左边描述了对游标结果的叠代,然后进行优化。游标的结果集会并行成N个分区,每个分区会进行这个循环体的逻辑,最后可能会有一个结果的SQL。下面的例子是对一个隐式游标做迭代,并对XY进行计算,其结果用来做一条SQL语句。第一步依然是分析出被叠代的游标,第二部是分析出这个结果的SQL,然后编译器内部会把循环体内部转换成小的UDTF。
微观优化的优点是无需修改业务逻辑,因为它是由编译器自动来完成,效率提升明显。缺点是对循环体内的控制流限制较多,因为有些语序是不能用的;对程序整体的数据流要求比较高,不能修改FOR循环之外的变量。
回复关键字,获取更多资讯
简介 | 产品 | 培训 | 投资 | 技术 | 视频监控案例集 | 运营商 | 税务 | 电商 | 医疗 | 金融 | 电力投资 | 交通 | 快递| Holodesk | TED视频 | 评测