本文档主要介绍了PolarDB MySQL版如何通过CBQT组件(Cost Based Query Transformation)实现基于代价的查询变换,从而大幅提升复杂查询的执行效率。
前提条件
集群版本需为PolarDB MySQL版8.0版本且Revision version为8.0.2.2.1及以上。您可以通过查询版本号确认集群版本。
背景信息
社区MySQL的查询变换主要是基于规则或者在局部变换的执行方式上考虑代价。而复杂的查询变换往往受到Cardinality、Access Method、Join Order等多种因素的影响,需要能够对复杂的查询变换生成执行计划的代价,才能选择到合适的变换。对于一些复杂的查询变换,PolarDB MySQL版会基于代价去选择是否变换,此功能可以通过添加CBQT组件(Cost Based Query Transformation)来实现。对于复杂查询,CBQT会收集该查询都可以做哪些基于代价的查询变换,这些变换会汇总成一个状态空间。CBQT会在该状态空间中选择生成执行计划代价最低的状态,执行对应的计划。如下图所示,对于输入的SQL,CBQT收集到基于代价的查询变换A和B,这两个变换组成的状态空间有:None(均不作变换)、A(只做变换A)、B(只做变换B)、AB(变换A和变换B都做)。这些状态空间分别对应不同的执行计划:Plan1、Plan2、Plan3、Plan4。CBQT会从中选择最优的执行计划,图中选择了Plan2,即查询变换A。
当前子查询利用GROUP BY解关联的变换就是基于代价的查询变换。此外,社区MySQL的derived merge也可以基于代价来选择查询变换。如下示例中,查询事实表f1
和维度表d1
做连接,事实表f2
和维度表d2
做连接,然后它们的结果再做左连接。社区MySQL中的derived merge是基于规则的查询变换,这种情况下会把d1
和d2
两个表都merge到上层query block中。
SELECT *
FROM d1
JOIN f1 ON d1.c1 = f1.c1
LEFT JOIN
(SELECT d2.c2 d2_c2,
f2.c3 f2_c3
FROM d2,
f2
WHERE d2.c1 = f2.c1) derived ON derived.d2_c2 = d1.c2
AND derived.f2_c3 = f1.c3;
上述查询经过derived merge后在MySQL中会形成如下的执行计划:在这个执行计划中,由于d1
和f1
与d2
和f2
之间没有索引关联,d1
和f1
连接输出的每一行都会驱动d2
和f2
做一次连接的重复计算,执行效率会大大降低。CBQT会通过分析得出这种场景的查询不做derived_merge查询效率会更高,从而生成新的执行计划,如下:在新的执行计划中,d2
和f2
的Join只需要执行一次,产生的结果集再和d1
、f1
做连接,从而大幅提升执行效率。
使用方法
基于代价的查询变换开关由参数cbqt_enabled控制,该参数默认为ON
。由于基于代价的查询变换会增加执行计划的搜索空间,同时增加一定的优化搜索时间。为了避免对短查询造成影响,cbqt_cost_threshold参数配置了考虑基于代价查询变换的代价阈值,只有代价超过该阈值的查询才会考虑基于代价的查询变换。对于社区MySQL的derived merge,在参数polar_optimizer_switch中由derived_merge_cost_based
开关进行控制,该开关默认为off
。具体参数说明请参见下表:
参数名称 | 级别 | 描述 |
cbqt_enabled | Global、Session | 基于代价的查询变换开关。取值范围:
|
cbqt_cost_threshold | Global、Session | 当查询的原执行代价超过该值时,对查询考虑基于代价的查询变换。 取值范围:0~18446744073709551615。默认值为100000。 |
cbqt_timeout | Global、Session | 为避免搜索合适的查询变换花费太多优化时间,当优化时间超过该值时,不再继续搜索。 取值范围:0~18446744073709551615。默认值为200。单位为毫秒。 说明 该值为0时,表示搜索时间无限制。 |
polar_optimizer_switch | Global、Session | PolarDB查询优化的控制开关。取值范围:
|
- 本页导读 (0)