暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

GaussDB倾斜优化特性(RLBT)引发的一个查询逻辑错误

原创 Quark 2021-07-31
1879

GaussDB分布式数据库中数据倾斜有两种,分别为存储层数据倾斜和计算层数据倾斜。在创建表时,如果未选择合适的分布列,则会导致数据不能均匀存储在各个数据节点,在SQL运行时,数据量较大的节点往往会成为性能瓶颈。对于存储层数据倾斜,目前只能通过选择合适的分布列重建表的方式进行规避。相比而言,计算层数据倾斜识别及优化的难度就比较高。
在我们遇到过的案例中,计算倾斜主要是由数据重分布导致的,由于在SQL语句使用了join关联、group by、over(partition by)窗口函数以及distinct等算子,数据需要按照指定的字段重新进行分布,这很可能会导致出现数据倾斜,因为在很多时候,参与重分布的字段往往不是一个理想的分布列。对于group by、over()、distinct算子引起的计算倾斜,优化方法主要是采用增加过滤条件,减少数据量来降低重分布带来的成本开销,或者是根据实际情况开启SMP并行,加快执行速度。如果计算倾斜来自于join关联,此时问题就变得相当棘手,在一些特殊情况下,常规的优化方法几乎无法做到提升性能。
针对这种现状,在GauuDB A 6.5.1版本中新增了RLBT(Runtime Load Balance Technology)方案,可以自动识别、解决运行时的计算倾斜问题。RLBT方案主要分为两个层面,第一步是计算倾斜识别,第二步是计算倾斜解决。计算倾斜的识别,即预先识别计算过程中的重分布列是否存在倾斜数据,RLBT方案中给出了三个解决手段,统计信息识别,hint方式指定以及规则识别。在解决倾斜时,目前针对最常见的join和agg算子进行了优化。有关RLBT方案详细内容可以参考GaussDB产品文档,在此我们只讨论该方案在一个特殊案例中的使用错误。
下面是案例中经过处理的SQL语句:

select t1.num_1,
       t2.account_1,
	   t2.party_id,
	   t2.fova
  from schema1.a03_edu_yyd_acct t1
  left join schema2.sch_par_account t2
    on t1.num_1 = t2.account_1
   and t2.bizno in ('01','11','12')
   and t2.flag = '1'
 where t1.date_sat = cast('20210731' as date)
   and t1.zonum < 5000
   and t1.num_1 = '203106';

上面的语句查询结果中表t2的字段均为空,如果on条件改为trim(t1.num_1)=t2.account_1,则t2的字段均可以关联出正确不为空的结果。需要说明的是,该语句在数据库升级之前运行正常,只是在升级之后才出现问题,也就是说,升级之前,t1.num_1 = t2.account_1,升级之后必须是trim(t1.num_1)=t2.account_1。
我们分别打印了上述两种情况的执行计划,从中可以看到,当on条件为t1.num_1 = t2.account_1时,执行计划使用了RLBT特性对数据倾斜进行了优化,当on条件为trim(t1.num_1) = t2.account_1时,执行计划未使用RLBT特性,t2表扫描的结果进行了broadcast。
1.png

使用了RLBT特性的执行计划

2.png

未使用RLBT特性的执行计划

由于t1.num_1 为关联列,且t1.num_1 = ‘203106’,所有数据在一个DN上面,所以该值是一个倾斜值。根据RLBT方案,外表t1的数据需要做PART_REDISTRIBUTE_PART_ROUNDROBIN,其中对倾斜数据做roundrobin,非倾斜数据做redistribute,在performance执行计划中可以详细的看到t1.num_1 = ‘203106’的这部分数据在部分DN上进行了roundrobin分布。对于内表t2,需要做PART_REDISTRIBUTE_PART_BROADCAST,其中对倾斜数据做broadcast,非倾斜数据做redistribute。由于t1.num_1 = ‘203106’,t1.num_1 = t2.account_1,优化器推导出t2.account_1=‘203106’,因此对于t2的倾斜值’203106’,要在所有节点上进行broadcast。但是,在performance执行计划中我们看到,t2的这条数据未做broadcast,而是做了redistribute,数据仅分布在了其中一个DN上。显然,RLBT特性认为,t2.account_1不等于t1.num_1。
从上面的分析可知,RLBT方案在进行倾斜优化时出了问题,把原本需要做broadcast的数据进行了redistribute,导致能够匹配的数据不在同一个DN上,这就是为什么t1.num_1 和 t2.account_1无法关联的原因。
通过分析代码,我们发现数据库中有一个参数string_hash_compatible控制着char类型和varchar/text类型的hash值计算方式,当该参数值为on时,计算hash值时不会忽略char类型后面的空格;当参数值为off时,则会忽略char类型后面的空格。由于t1.num_1的数据类型为char(8),t2.account_1的数据类型为varchar(6),数据库中该参数值为on,优化器认为’226402’的 varchar(6)类型的值和char(8)类型的值是同一个类型,因此没有做类型转换,导致后面在做倾斜值比较的时候,对这两个值计算出的hash值不同,从而判断倾斜值出现问题,认为在表t2上’226402’这个值不是倾斜值,从而对t2.account_1做了REDISTRIBUTE,匹配失败。
参数string_hash_compatible影响重大,在生产环境中不建议修改。如果SQL代码也无法进行调整,可以将RLBT控制参数skew_option设置为off,关闭该特性,避免倾斜优化错误。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论