关于云计算:谈谈in常量查询的设计与优化

12次阅读

共计 4086 个字符,预计需要花费 11 分钟才能阅读完成。

介绍

如题目所示,这是一篇介绍 in 常量查问的源码解读文章,但又不限于 in 常量查问,因为其中波及的很多设计与优化对于大多数查问都是普适的。一如平常一样,咱们首先会过一遍整体的执行流程,梳理一个大抵的框架。紧接着,同时也是更重要的,咱们会通过一系列在实在场景中遇到的问题(说白了就是性能优化),来对各种细节解决进行加强。

舒适揭示:倡议有条件有趣味的同学能够对照着本篇文章边调试(我基本上把重要的断点地位都截了图)边学习边思考,这样印象和了解应该会更加粗浅。

心愿大家在读完之后,能够尝试着答复以下一些问题来进行某种测验:

  • 什么是分片裁剪?为什么要进行分片裁剪?
  • 为什么要对物理 SQL 中值进行裁剪?
  • 什么是 plan cache?为什么须要?
  • 为什么须要 post planner ?
  • XPlan 是什么?为什么 Xplan 比物理 SQL 更优?
  • 为什么要有一个 ToDrdsRelVisitor?
  • 什么是全局二级索引?如何利用?
  • 以及其余散落于文章中或者浏览时的问题

从大抵的流程说起

注:具体的执行流程请参考文章,https://zhuanlan.zhihu.com/p/…,咱们这里只介绍其中几个比拟重要的环节。咱们拿一个非常简单的场景来看一下吧,一个简略的表如下,create table t(c1 int, c2 int, c3 int) dbpartition by hash(c1) tbpartition by hash(c1) tbpartitions 2,一条最简略的 SQL 如下:select c3 from t where c1 in (1,2)。挑了五个阶段进行了并不太详尽的阐明,如果你感觉比拟形象时,也能够入手调试一下,一些概念应该就会更加清晰了。

阶段一

咱们须要将 SQL 文本解析为语法树,如果不非法,则报错,要害断点如下图,其中 sql 为输出的查问语句,statement 为通过解析后的语法树。

须要留神的是,在这个中央,咱们是只进行语法解析,而不进行语义解析。什么意思呢,比方你当初输出的 SQL 为 select c1 from tt,此时尽管咱们没有 tt 这张表,然而断点处还是会失常解析出一个 SQLSelectStatement,有趣味的同学能够打个断点试一下。

阶段二

如上剖析,咱们当初要进行语义的校验了,比方我怎么晓得这张表存不存在,以及是否含有这个列呢?

阶段三

构建执行打算,在 toRel 时将由 SqlNode 形成的 AST 转换为由 RelNode 组成的逻辑打算。

埋一个坑把,有趣味的同学能够联合代码思考一下,既然咱们曾经拿到了逻辑执行打算,那么 ToDrdsRelVisitor 的作用是什么呢?

阶段四

对执行打算进行优化,以期取得较为优异的执行成果。

阶段五

拿到执行打算之后,紧接着咱们来看一下是在哪里执行的,以及是如何执行的

咱们能够简略看一下这个 plan,这是一个非常简单的 plan,最上层是一个 Gather 用来聚合上层多个 logicalView 的后果,而 logicalView 中蕴含了如何与存储节点进行交互的信息。依据 plan 拿到相应的 handler,而后进行调用就能够了。

在这个场景中,咱们会递归调用 logicalView 的 handler。

OK,以上就是一个大略的执行流程,接下来咱们来真正深刻到一些细节看一下,咱们如何将这个大抵的流程进行丰盛以使其可能满足工业生产的需要。

事实中的应用场景

In 查问列表中的值不固定,个数亦不固定。

优化思路

单条 SQL 的优化,比方分片裁剪,物理 SQL 中 in 值的裁剪,应用 XPlan 代替物理 SQL。
大量执行类似的 SQL 时,防止重复性且不必要的工作,如防止每次从新生成 plan。
对其中一些非凡场景进行更加极致的优化,比方单分片间接下推。
通过增加索引进行优化,在这里咱们次要探讨全局二级索引。

具体的优化

单条 SQL 的优化

分片裁剪:只拜访必须拜访的分片

Q:select from t where c1 in (1,2) 会向所有分片下发物理 SQL 么?
A:不会的。通过下面的剖析,咱们下发的物理 SQL 为 select from t_physical_table where c1 in (1,2),t_physical_table 为逻辑表 t 所对应的物理表。而因为表 t 的分库键和分表键均为 c1,因而显然咱们只须要向两张可能存在匹配记录的物理表下发物理 SQL 即可,获取裁剪后的分表信息如下图。

分片裁剪是肯定须要调用分片计算,分片计算的逻辑在这里。

物理 SQL 中 in 值的裁剪:只留下有用的 in 值

Q:下发的物理 SQL 中,是否会对 in 的列表进行裁剪呢?
A:会的,而且对下发的物理 SQL 中的 in 列表中的值进行裁剪,次要有两个益处,一是尽可能防止下发的物理 SQL 导致不必要的全表扫描,二是缩小下发物理 SQL 的长度。

上图中 PruneRaw 即代表裁剪后的 in 查问列表。

应用 XPlan 代替物理 SQL:防止 DN 节点进行物理 SQL 的解析优化

注:详情可参考链接文章中的执行打算传输局部,https://zhuanlan.zhihu.com/p/…,%E8%BF%9B%E8%A1%8C%E4%BA%86%E7%89%B9%E6%AE%8A%E4%BC%98%E5%8C%96%E3%80%82 Notice:in 查问其实临时是不反对传输执行打算的。但我感觉可能没什么特地非凡的中央,像传输其余的 plan 一样,咱们须要在计算层指定数据的拜访形式(即指定索引),而后进行适配和对接。

防止每次从新构建 plan

防止参数值不同而重复构建 plan

Q:每次都进行 plan 的构建,看起来并不是十分有必要,比方 select from t where id in (1,2) 和 select from t where id in (2,3)。
A: 是的,所以咱们对 plan 进行了缓存,这就是 PlanCache 组件,能够了解为 Map。很天然的,咱们须要对上述两条 SQL 进行参数化以便从 map 中进行查找,即参数化为 select * from t where id in (?,?) 的模式,代码在

防止参数个数不同而重复构建 plan

Q:仔细的同学可能感觉有点奇怪,下面的 select c1,c3 from t where c1 in (1,2) 参数化后为 select c1,c3 from t where c1 in (?),而非 select c1,c3 from t where c1 in (?,?),这是为什么?
A:这样做是为了防止 plan cache 的收缩,因为这样参数化之后,select c1,c3 from t where c1 in (1,2) 和 select c1,c3 from t where c1 in (1,2,3,4) 就是共用一个 plan cache 了;此外,这样还能够缩小参数化 SQL 占用的内存,设想一下,有些 SQL 中 in 列表中的值多达几十万个呢。

单分片场景优化

Q:对于某些场景,是否有更近一步的优化,毕竟 TP 是须要尽可能的高性能的。
A:有的,比方单分片的场景,in 列表中的值会落在同一个物理分表上。咱们能够思考下此时上面的执行打算是否能够简化?

答案是显然的,在单分片场景下,下层的 Gather 是齐全不须要的,否则咱们在执行时会有额定的执行开销。引申:咱们能够再联合后面的参数化与 plan cache 来了解这个问题,即参数不同的 SQL 的最优执行打算其实并非总是雷同的,但咱们为了防止每次反复生成 plan,又会缓存一个 plan,于是咱们须要一个可能对 plan 进行优化的能力。咱们大略能够把这种状况分成两种,一种是参数不同导致抉择的 join 算法不同,比方是抉择 bka join 还是 hash join,为了解决这个问题,咱们引入了执行打算治理模块(SPM);另一种则跟咱们的架构有十分大的关系,因为咱们上层的 DN(能够简略了解为 mysql)显然是具备执行各种 SQL 的能力的,而如果在某些参数下,通过裁剪后只剩下一个分片了,则该 SQL 通过物理表名的替换后可间接下发到 DN 执行,计算层只须要期待后果返回即可,无需做任何其余的操作。为了实现第二种成果,咱们在 planner 阶段减少了一个阶段,叫做 post planner,在 post planner 中会判断是否可能下推到某个分片,默认为关上,上图中为了演示须要,特意应用 hint 进行了敞开。

增加全局二级索引

注:索引,实质是一种批改与查问的衡量,须要用户审慎思考,尤其写入全局索引会带来较大的分布式事务开销。

Q:分片建曾经确定了,in 查问的字段没有跟分片对齐,是不是无奈做分片裁剪了,还能优化么?
A:能够思考减少全局二级索引。咱们来举个例子吧,比方 table: t3(c1 int, c2 int, c3 int) dbpartition by hash(c1); SQL 为 select c3 from t3 where c2 in (1,2),由执行打算可知咱们无奈进行分片裁剪,因而须要拜访所有 8 个分片,如下:

当初让咱们来考虑一下如何优化?咱们的目标是心愿缩小拜访的分片数,而之所以无奈进行分片的裁剪,是因为 in 查问的字段和分片键没有对齐。于是解决方案也很简略,咱们减少一个拆分键与 in 查问字段对齐的全局的二级索引即可,无关全局二级索引的介绍,可参考链接,https://help.aliyun.com/docum…。比方,咱们执行如下增加全局二级索引的 SQL,alter table t3 add global index g_c2(c2) covering(c1, c3) dbpartition by hash(c2),而后咱们再来看下此时的执行打算,发现此时曾经如咱们所料进行了基于全局二级索引的分片裁剪,当初只须要扫描两个分片即可。

一个小练习

In 列表中蕴含大量反复值时,能够如何优化?(咱们当初的版本没有思考这种状况)比方,有一个很简略的做法,在参数化时加一个去重,如下图。

而后大家能够思考一下,须要留神什么,以及有什么问题么?

One More:横向比照与思考

大家有趣味,有工夫的,能够比照其余友商数据库进行比拟与剖析。

总结

其实我在这篇文章外面,抛了挺多问题,有些给了一种便于叙述却未必全面的答案,有些则齐全没有答复。最初的这个总结我感觉也留给大家来写了。

原文链接

本文为阿里云原创内容,未经容许不得转载。

正文完
 0