揭秘 TiDB 新优化器:Cascades Planner 原理解析

TiDB 当前优化器简介

关系型数据库中查询优化器的作用是为一个 SQL 在合理的开销内产生一个合适的查询计划, TiDB 源码阅读系列文章(六)Select 语句概览 中介绍过 TiDB 当前优化器的基本组成,TiDB 当前的优化器将优化过程主要分为逻辑优化(Logical Optimize)和物理优化(Physical Optimize)两个阶段。逻辑优化是将一棵逻辑算子树(LogicalPlan Tree)进行逻辑等价的变化,最后的结果是一棵更优的逻辑算子树;而物理优化则是将一棵逻辑算子树转换成一棵物理算子树(PhysicalPlan Tree)。这棵物理算子树就是我们说的物理执行计划,将交由 TiDB 执行引擎去完成后续的 SQL 执行过程。

逻辑优化

TiDB 中,一个 SQL 在进入到逻辑优化阶段之前,它的 AST(抽象语法树)已经转换成了对应的逻辑算子树,因此逻辑优化就是将一个逻辑算子树进行逻辑上等价变换的过程。逻辑优化是基于规则的优化(Rule-Based Optimization,RBO),这些规则背后的原理就是关系代数的等价变换,其中典型的规则包括:列剪裁,谓词下推等。TiDB 现有逻辑优化规则的原理和实现可以参考这两篇源码阅读文章: (七)基于规则的优化 , (二十一)基于规则的优化 II 

随着 TiDB 中逻辑优化规则的不断增多,逐渐暴露了当前优化框架存在的几个问题:

  1. 优化器要求每个逻辑优化规则一定是有收益的,转换后得到的逻辑执行计划必须比转换前的更优(例如谓词下推),但是某些优化规则只在特定场景下有收益(例如聚合下推 Join),这种优化规则很难添加到目前的优化器中,导致优化器在那些特定场景下的执行计划不够优。

  2. 不管什么样的 SQL,在逻辑优化阶段,所有的优化规则都按照同一个固定的顺序依次去看是否能够作用于当前的逻辑执行计划,例如最先执行的规则总是列剪裁。逻辑优化规则之间的顺序需要经过有经验的优化器老手精心的安排,例如分区表处理(PartitionProcess)要在谓词下推后进行。这就导致所有人在添加优化规则的时候都需要小心翼翼地安排这个顺序,添加一个优化规则需要了解其他所有优化规则,门槛较高。

  3. 逻辑优化阶段,每个规则至多只会在被顺序遍历到的时候执行一次,但实际场景中,往往存在之前某个已经执行过的优化规则可以再次被执行的情况。我们以一个例子来说明,对于这个简单的 SQL:select b from t where a > 1,其中 a是 int类型的主键,我们最终会产生这样一个物理执行计划:

    TableScan(table: t, range:(1, inf]) -> TableReader(a, b) -> Projection(b)
    

    在 TableReader 的 Schema 中包含了 ab两列,也就是说 TiDB 会从 TiKV 中读取两列内容,但最终自己却只需要其中第一列。这个问题背后的原因是:优化器先进行列裁剪,再谓词下推,但是谓词下推之后,有可能列剪裁可以再次生效,而这个可能生效的列剪裁在现在优化器中无法被执行了,导致 TiDB 从 TiKV 多读取了一列数据,增加了 SQL 执行时的网络 IO 使用量。

物理优化

物理优化是一个将逻辑算子树转化为物理算子树的过程,我们在之前的 TiDB 源码阅读系列文章(八)基于代价的优化 中做过详细的介绍。在物理优化中,优化器会结合数据的分布(统计信息)情况来对查询计划进行优化,物理优化是一个记忆化搜索的过程,搜索的目标是为逻辑执行计划寻找满足特定物理属性的物理执行计划,并在其中选择代价最低的作为搜索结果,因此也被称为基于代价的优化(Cost-Based Optimization,CBO),例如 DataSource 应该选择怎样的扫描路径(使用哪个索引),Join 应该选择怎样的执行方式(HashJoin、MergeJoin 或 IndexJoin)等。

在 TiDB 中,物理优化不仅仅是选择物理算子,还完成了算子下推 TiKV 的任务,例如将 Aggregation 算子分裂成 FinalMode 和 PartialMode 两部分,并将 PartialMode 的 Aggregation 下推到 TiKV Coprocessor 中执行,具体可以参考 TiDB 源码阅读系列文章(二十二)Hash Aggregation 

目前支持下推的算子有:Selection、Limit、TopN 和 Aggregation,下推的方式有两种:

  • 对于 Selection 算子,由于 Selection 在逻辑优化阶段被下推到 DataSource 中,因此在物理优化阶段中,如果 Selection 中有过滤条件不能转换成扫描的 Range 条件,就会产生一个 Coprocessor 层的 Selection。

  • 对于 Limit、TopN 以及 Aggregation 算子,当且仅当它们的子节点是 DataSource 的时候,才允许被下推。

下图展示了一个简单的聚合查询如何经过优化得到最后的物理计划:

  1. 首先在逻辑优化阶段,Selection 中的过滤条件会被下推到 DataSource 中的 AccessConds 中。
  2. 在物理优化阶段其中的 A.pk > 10会转换为主键的范围条件,而 A.value > 1则会产生一个 TiKV 层的 Selection。
  3. 同时由于 Aggregation 的子节点是 DataSource,因此也会被下推到 TiKV 中。

上述的物理优化过程,存在几个潜在的问题:

  • 算子下推逻辑过于简单,除了 Selection 之外只允许下推一个算子,难以应对未来添加的新的下推算子(例如 Projection 等),同时也没法针对某些特殊场景进行灵活地算子下推。

  • 扩展性差:难以扩展支持其他的存储

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

每天读点书学堂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值