了解 GaussDB 性能调优之隐式转换,解决慢 SQL 问题
一、问题现象
某项目上一段慢 SQL,相关技术人员反馈条件中用到 a.systemdate >= 20240422 and a.systemdate <= 20240422 执行耗时,而把条件改为 a.systemdate = 20240422 这样的点查询后,执行耗时就变快了。用户认为这两个条件是一样的,那优化器生成的执行计划也应该要一样。
二、技术背景
SQL 执行计划是一个节点树,显示 GaussDB 执行一条 SQL 语句时执行的详细步骤。每一个步骤为一个数据库运算符。
使用 EXPLAIN 命令可以查看优化器为每个查询生成的具体执行计划。EXPLAIN 给每个执行节点都输出一行,显示基本的节点类型和优化器为执行这个节点预计的开销值。影响 SQL 语句计划的优劣有很多方面,其中表的字段类型应使用一致的数据类型,表关联列尽量使用相同的数据类型。如果表关联列数据类型不同,数据库必须动态地转化为相同的数据类型进行比较,这种转换会带来一定的性能开销,也称为 “隐式转换”,也会影响到优化器生成的执行计划的不同。
三、处理过程
3.1 创建表结构 DDL 定义
3.2 执行计划分析
针对上面 systemdate >= 20240422 and a.systemdate <= 20240422 这个条件计划优化器估算的不准,导致执行算子 NestedLoop。
而对于条件 a.systemdate = 20240422 这种写法,优化器的估算让它执行算子 hasjoin。
条件的这两种写法,看起来是一样的,执行结果等价的啊,为什么 GaussDB 优化器解析的执行计划又不同了呢?
第一种条件 a.systemdate >= 20240422 and a.systemdate <= 20240422 下,客户提供的的执行计划如下:
注:上图可以看到优化器基于 cost 估算的值,让它走了 Nested Loop 的方式,导致最终 actual time=38564.806ms。上面有一个 Select Partition 1..2 是由于 d 表没有条件,并不是只有分区键一个字段关联了,就一定会走分区剪枝的,所以走了全表扫描(要想走分区剪枝,必须得具备有剪枝的条件)。
第二种条件 a.systemdate = 20240422 点查下的执行计划如下:
注:上图可以看到优化器基于成本估算的值,让他走了 hashjoin 的方式,导致最终 actual time=110.894ms。
四、处理结果
把 test1 表字段 sno 跟关联表 test2 表字段 sno 的数据类型修改为一致后测试,避免进行隐式转换,计划执行规则路径,计划执行时间由 actual time=38564.806ms,提升到 actual time=110.894ms。
五、总结
条件 1:a.systemdate >= 20240422 and a.systemdate <= 20240422 -- actual time =38564.806ms
条件 2:a.systemdate = 20240422 -- actual time = 110.894ms
上面两个条件写法虽然在逻辑上是等价的,优化器可能会认为有多个可能的结果(尽管实际上只有一个),两个条件的成本估算的值不同,走的 join 方式就不一样了,进一步导致执行计划的时间就有差别。
华为开发者空间,汇聚鸿蒙、昇腾、鲲鹏、GaussDB、欧拉等各项根技术的开发资源及工具,致力于为每位开发者提供一台云主机、一套开发工具及云上存储空间,让开发者基于华为根生态创新。点击链接,免费领取您的专属云主机
评论