优化器在数据库中一直位于至关重要的位置,性能调优也常常需要围绕优化器来进行。作为数据库厂商,我们希望在各类复杂的业务场景中,TiDB 都能够给出比较理想的执行计划,因此在优化器和执行器上做了非常多的工作和努力,但是选错执行计划或者索引的情况仍然是日常中最为常见的一个问题。
优化器有关的问题可以简单归结为两种:
- 统计信息准确的情况下给出了错误的执行计划。
- 另一类则是在统计信息过期的情况下给错了执行计划。
选错索引是其中比较常见的一种情况,用户希望添加索引来加速查询速度,某些情况下,优化器可能会走到全表扫的物理执行计划或者选错索引使得实际执行效果退化成全表扫的情况。
针对上述情况,我们需要从更微观的层面来度量优化器的执行计划和索引选择的性能,评估在优化器上做的改进工作能否切实起到期望的效果。
为什么我们要开发 Horoscope?
为了测量优化器和执行器,从去年开始我们构建了daily benchmark 平台 perf.pingcap.com,覆盖常见的几种复杂查询的测试场景,包含 TPC-H、TPC-DS、Star Schema Benchmark 等,跟踪每天开发分支上这些查询的执行速度情况。
通过 daily benchmark,我们观测和定位到了若干次性能提升以及性能回退的情况。有些提升或者回退是优化器组件上的优化导致的,有些则是 TiDB 其他组件,或者存储层引发的。
虽然 daily benchmark 能够观测到性能改进或者回退,但是对于以下几个问题它却束手无策:
- 当前选择的执行计划是否最优?选择率估计是否准确?
- 是否选择到了正确的索引?
- 现有的启发算法能否应对统计信息一定程度的过期?
因此,我们需要另外一种更系统的测试工具,用于优化器的测量。
Horoscope 是如何做的?
要测量优化器,我们需要:
- 定义优化器的性能指标
- 遍历执行计划空间
- 数据集以及查询生成
定义优化器的性能指标
这里我们参考“OptMark: A Toolkit for Benchmarking Query Optimizers”给出的方法来度量优化器有效性。简单地讲某个查询的有效性指标,是指在可遍历的执行计划空间中,优化器选出的默认执行计划的执行时间比其他的执行计划的执行时间更快的比例。
例如 100% 可以解释为默认执行计划的执行时间比其他执行计划的执行时间都更快,50% 解释为有一半的执行计划要比默认执行计划更快。
遍历执行计划空间
由于需要一种方式能够让 TiDB 按照我们所指定的物理执行计划来实际执行查询,为此我们在 TiDB 中添加了 nth_plan(n) 这个 SQL hint。
当查询语句提交到 TiDB 后,TiDB 会为搜索空间中的每个执行计划绑定一个固定的序号,通过这个序号我们就能指定优化器去选择哪一个执行计划。
n