基于代价的优化器
通常,我们把 SQL 查询优化器分为两种类型:
RBO(Rule Based Optimizer)
CBO(Cost Based Optimizer)
RBO 顾名思义,就是事先定义好一系列的规则,然后去遍历这些规则做优化。
而 CBO,自然就是根据所谓的代价去做优化,代价最小的执行计划就是最好的执行计划。
RBO 固然是好的,能解决很多问题。
这是上一篇文章里的例子,一个很简单的查询,对应的执行计划是这样:
通过两个常见的规则转换,就能得到下面这个更好的执行计划:
RBO 好不好,很好嘛,project 和 filter 都 push down 之后不就能大大减小数据量了,性能不就好了嘛。
但是 RBO 还不够好:
规则是基于经验的,经验就可能是有偏的,总有些问题经验解决不了
不太可能列出所有经验,事实上这些规则也确实是逐渐充实的
Hive 里的 CBO
Hive 在 0.14 版本引入了 CBO,典型的,由于 join 是 SQL 中非常影响性能的操作,所以引入之初就解决了下面几个大难题:
Join Ordering Optimization
Bushy Join Support
Join Simplification
很显然,我们光看名字就知道,这几个问题不是 RBO 能解决了。篇幅有限,我们只看第一类情况。
这个例子来自 TPC-DS Q3,比刚才那个例子稍微复杂一点。但也就是多了一张表一起 join,再多一些过滤条件。
很显然,这个查询依然能受益于 RBO 里的 push down 规则。另外留意下,两个表过滤之后的行数是这样:
下面对比下,RBO 之后的执行计划是这样:
而经过 CBO 之后的执行计划是这样的:
可以看到,store_sales join item 之后的结果只有 82 million 行,比默认的 store_sales join date_dim 的 14 billion 行少了一个数量级了。
不同的 join 顺序带来的性能差距是巨大的。实际的性能测试结果会更直观:
很显然,RBO 是没法做到这点的。没法总结出这么条规则,来判断哪个表应该放在 join 顺序的前面。
那 CBO 又是怎么做到的呢?
定义代价模型
不难看出,上面的例子中,主要是通过这么两点来判断 join 顺序的:
原始表的行数
过滤之后的行数
说白了,就是行要少,无论是原始数据的行,还是中间结果的行,越少性能越好。
那是不是就用行来衡量代价就够了呢?
没这么简单,因为影响性能的不只有行<