热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

表关系join和where性能差异原因_查询性能提升利器:CirroData之joinorder选择算法...

全文约3836字,阅读约23分钟数据库查询的快慢一般情况下和查询性能有很大的关系,这也是在数据库设计时需要重点考虑的问题。CirroData数据库面向P

4a1f3d6cad2aca42c98a5da4d3182dc5.png

全文约3836字,阅读约23分钟

数据库查询的快慢一般情况下和查询性能有很大的关系,这也是在数据库设计时需要重点考虑的问题。CirroData数据库面向PB级海量数据分析应用领域,通过引入CBO,即Cost-Based Optimizer(CBO),来根据CPU、内存以及I/O的开销进行查询的优化。CirroData的CBO通过对查询语句中的表做定量分析,并利用join order选择算法评估可行的查询计划,可以在大多数情况下选出令人满意的执行计划,提高查询性能。本文将从开发者的角度介绍join order选择算法,探索其原理和实现,而这也从某一方面回答了“CirroData的查询性能为何如此高效?”这一问题。b1c5251a9bbf60d4a79bb11407357b95.png1join order选择算法的重要性

在有限的搜索空间下,表连接的排列组合数会随着表个数的增加而迅速增长,如果这个组合数量巨大,连接次数显然是一个很高的数量级,最大可能的连接次数是N!,例如参与连接的基表个数为5时,表连接次数为120次;参与连接的基表个数为10时,表连接次数达到了3628800次!

显然,数据库使用者在复杂数据查询场景下编写SQL脚本时,难以对结果进行预判。这时,就需要引入优化器,在有限的时间内找出最优的解决方案。Cost-Based Optimizer(CBO) 是数据库查询优化中一种常用的优化器,其通过对表的统计来决定对于结构化查询最有效的查询执行计划。

CBO 中的 join order 选择算法对于海量数据查询而言,是性能提升的第一重要技术手段。Join order 选择算法简单来说就是从可行的 join order 中挑选出一个最好的,但是要在有限的时间和空间下做好这件事却是数据库中的难题之一。对于复杂的Join算子优化,采用不同的join order,花费CPU资源、内存资源的差异会比较大,这也意味着不同的join order有不同的执行效率。

例如,A join B join C,A、B表都很大,C表很小,那A join B很显然需要大量的系统资源来运算,执行时间必然不会短。但是使用A join C join B的执行顺序,A与较小的C表join必然会很快得到结果,且结果集会很小,再使用生成的小的结果集与B做连接,性能显然比第一种方案好。因此找到一个好的连接顺序,对于查询的性能至关重要。

b1c5251a9bbf60d4a79bb11407357b95.png2常见的join order选择算法

目前流行的数据库中,针对join order选择普遍采用的算法包括动态规划算法、贪心算法、遗传算法等。动态规划算法需要遍历全部解空间,但一定可以获得最优解,是最优化算法的一种;而贪心算法和遗传算法都属于启发算法,即基于直观或者经验构造的算法,在可接受的花费(指计算时间和空间)下给出待解决组合优化问题每一个实例的一个可行解,该可行解与最优解的偏离程度一般不能预计。

表3-1对动态规划算法和贪心算法进行了简单的对比:

2a3b1076fd4d54041d7099a3e63f4a1c.png

常见的数据库中,PostgreSQL和GreenPlum在表数目较少时采用了动态规划算法,表数目较多时采用遗传算法来解决该问题;而MySQL则主要通过贪心算法来实现join order的选择。

我们在制定CirroData数据库的设计方案时,充分考虑到了CirroData分析型数据库面向的PB级海量数据查询场景,采用了动态规划算法和贪心算法相结合的策略,以达到最佳查询效率。

b1c5251a9bbf60d4a79bb11407357b95.png3CirroData使用的join order选择算法

动态规划算法需要遍历全部解空间,一定可以获得最优解,因此它是CirroData的首选方案。但是即使CirroData已经基于表之间的连接关系对搜索范围做了较为仔细的范围限定,算法搜索的可能组合数仍会由于表的增多,造成巨大的搜索耗时。

因此CirroData在对join order选择的过程中采取的策略是,当参与join的表个数不超过8时,采用动态规划算法,超过8时采用贪心算法。

3.1 基于动态规划的join order选择算法

当表数量较少时,CirroData采用迭代的方式,从单个表出发,先初始化基表的代价,然后尝试求两个表的最优join order,再逐步迭代求解3个表、4个表...,从而穷举得到最优的join order。

显然穷举会造成过多的join order组合,但是实际开发中会基于表之间连接顺序的限制进行剪枝操作,另外由于动态规划本身会记录重复的子问题、连接路径建立也是一个优胜劣汰的过程等因素,有些组合并不会出现,这也在一定程度上控制了算法的时间复杂度。具体可以通过下面的例子了解CirroData基于动态规划的join order选择算法的具体过程。

例:  SELECT * FROM A, B, C, D

WHERE A.col=B.col AND A.col=C.col AND A.col=D.col;

初始化——构造第一层关系,假设使用path结构存储连接路径,则叶子节点表示为path [1],在第一层中,每个关系的最优路径就是这个基表本身,如图3-1所示:

39fb2583d47b90b2a6f0ede024ae46fe.png

图3-1 待连接的基表

归纳——假设已经生成1~L-1层子树&#xff0c;则求解第L层的关系&#xff0c;在满足join key和连接顺序限制的基础上尝试生成左深树和紧密树如图3-2所示&#xff0c;直到最终找到最优join order。具体求解过程可参考表3-2&#xff0c;其中L表示当前生成连接树的总层次&#xff0c;L <&#61; 总基表数&#xff0c;其中L左表示当前待连接的关系左侧的连接树&#xff1b;L右表示当前待连接关系右侧的连接树&#xff0c;L左&#61; L - L右。

d03ca85ea4b0caa6f182473e7e157bdf.png

图3-2 左深树和紧密树

表3-2基于动态规划的join order构造过程

dedbd858dbb84800eb1fd179c09d49e4.png

为了更清楚的描述紧密树的生成方式&#xff0c;本例再增加两个参与join的基表E&#xff0c;F&#xff0c;通过表3-3描述了6个表做join的时候生成紧密树的过程。左深树的生成过程与上例相似&#xff0c;不再赘述。

表3-3 紧密树的生成

fafd90256ad3b7f07d0a335607b5af7d.png

3.2 基于贪心的join order选择算法

当表数量超过8个时&#xff0c;CirroData采取贪心算法来进行join order的选择。进行贪心选择之前&#xff0c;需要对参与join的基表&#xff0c;基于优先级规则进行排序&#xff0c;因为小表会产生更小的代价&#xff0c;在满足语义的前提下应该尽可能的把元组个数少的的基表排在前面&#xff0c;排序的优先级如下。

  • 依赖关系&#xff0c;例如A left join B&#xff0c;则B依赖于A&#xff0c;排序后A应该在B前面&#xff1b;

  • 键引用关系&#xff0c;当表A的某个列作为外连接关系连接列或者作为条件使用时&#xff0c;认为该表将来的行数有几率变小&#xff1b;

  • 表的元组数&#xff0c;表的元组数少的&#xff0c;排在前面&#xff1b;

  • 内存地址&#xff0c;比较表在内存中的位置&#xff0c;即指针地址小的在前面。

相对动态规划算法&#xff0c;CirroData基于贪心的join order选择算法不会再穷举所有的join order&#xff0c;本文通过下面的例子描述CirroData基于贪心的join order选择算法的具体过程。为了方便描述&#xff0c;例中仅以5个基表描述基于贪心的join order选择算法&#xff0c;实际应用场景中join order的构造过程与之类似。

例:  SELECT * FROM A, B, C, D,E

WHERE A.col&#61;B.col AND B.col&#61;C.col AND C.col&#61;D.col AND D.col&#61;E.col;

本例假设没有依赖关系和建引用关系&#xff0c;搜索深度为2&#xff0c;构造过程详见表3-4。其中L表示当前生成的左深树的总层数&#xff0c;best_ref表示使用深度搜索算法获得待定的局部最优解&#xff0c;最终选出的join order也会保存在这里&#xff0c;position表示在待定的局部最优解best_ref基础上贪心选择出的确定的局部最优解。

每次贪心选择之前都会将已得到的局部最优join order与即将加入的基表及其以后的depth个没有连接过的基表进行一遍深度优先搜索&#xff0c;根据表的代价和限制关系查找新的局部最优解。之所以说是局部的&#xff0c;是因为深度优先搜索的搜索深度限制&#xff0c;这个限制可以避免表数量过多造成的大数量级连接组合的情况。在深度优先搜索算法递归调用的过程中&#xff0c;深度会逐层递减&#xff0c;查询树也从叶子逐步向上层构造。

贪心算法体现在每一次深搜的结果总认为是本次循环得到的最优结果&#xff0c;并且从best_ref中取出第一个表作为确定局部最优解的一部分&#xff0c;为下一次连接提供依据。当构造的join order的搜索深度等于表的个数&#xff0c;或提前构造出最优的join order(深搜遍历到最后一层把可连接的基表用光了&#xff0c;没有可连接的基表了)时&#xff0c;join order构造过程结束&#xff0c;得到的最优join order存储在best_ref中。

表3-4 基于贪心的join order构造过程

5cf3a62373c9a8a8c3b37a5f65b5e9ae.png

通过了解算法中两个边界情况&#xff0c;可以更清晰的理解基于贪心的join order算法&#xff0c;因为其他情况皆介于二者之间。

当参与JOIN的表的个数小于depth时&#xff0c;基于贪心的join order选择算法将退化为一个深度优先的穷举算法确定最优执行计划&#xff1b;

当depth &#61; 1的时候&#xff0c;函数退化为"极其"贪婪的算法&#xff0c;每次从当前的剩余的表中取一个代价最小的&#xff0c;来扩展当前的执行计划。

b1c5251a9bbf60d4a79bb11407357b95.png4综述和展望

CirroData的Join order选择算法为执行计划找到了更好、甚至最好的连接顺序&#xff0c;在大多数情况下提升查询语句的执行效率&#xff0c;这正是CirroData开发工作者愿意深入探索的原因之一。

但是考虑到对CirroData查询性能的进一步优化&#xff0c;想要通过CBO获得更满意的性能效果还要更多的依赖基数估计和代价模型的准确性&#xff0c;但是实际上当前CirroData的基数估计模型和代价模型&#xff0c;尤其是代价模型还有待完善。

因此&#xff0c;CirroData在探索合适的join order选择算法的同时&#xff0c;如何更好的进行基数估计和查询子树各类关键算子的代价估计也是一个值得关注的问题。

参考文献

1.李海翔. 数据库查询优化器的艺术--原理解析与SQL性能优化&#xff1b;

2.张树杰. PostgreSQL技术内幕&#xff1a;查询优化深度探索&#xff1b;

3.Viktor Leis等. How Good Are Query Optimizers,Really。

e382bee28cfdb776a6447da54c8dfb2e.png




推荐阅读
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 基于PgpoolII的PostgreSQL集群安装与配置教程
    本文介绍了基于PgpoolII的PostgreSQL集群的安装与配置教程。Pgpool-II是一个位于PostgreSQL服务器和PostgreSQL数据库客户端之间的中间件,提供了连接池、复制、负载均衡、缓存、看门狗、限制链接等功能,可以用于搭建高可用的PostgreSQL集群。文章详细介绍了通过yum安装Pgpool-II的步骤,并提供了相关的官方参考地址。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 基于事件驱动的并发编程及其消息通信机制的同步与异步、阻塞与非阻塞、IO模型的分类
    本文介绍了基于事件驱动的并发编程中的消息通信机制,包括同步和异步的概念及其区别,阻塞和非阻塞的状态,以及IO模型的分类。同步阻塞IO、同步非阻塞IO、异步阻塞IO和异步非阻塞IO等不同的IO模型被详细解释。这些概念和模型对于理解并发编程中的消息通信和IO操作具有重要意义。 ... [详细]
  • Tomcat/Jetty为何选择扩展线程池而不是使用JDK原生线程池?
    本文探讨了Tomcat和Jetty选择扩展线程池而不是使用JDK原生线程池的原因。通过比较IO密集型任务和CPU密集型任务的特点,解释了为何Tomcat和Jetty需要扩展线程池来提高并发度和任务处理速度。同时,介绍了JDK原生线程池的工作流程。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • Oracle Database 10g许可授予信息及高级功能详解
    本文介绍了Oracle Database 10g许可授予信息及其中的高级功能,包括数据库优化数据包、SQL访问指导、SQL优化指导、SQL优化集和重组对象。同时提供了详细说明,指导用户在Oracle Database 10g中如何使用这些功能。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
author-avatar
心理学点滴_312
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有