GaussDB(DWS)性能调优:性能问题闭环总结(三)——聚合慢 + SQL未向量化执行

举报
O泡果奶~ 发表于 2024/02/06 09:45:10 2024/02/06
【摘要】 【摘要】 本文是作者结合实际调优案例总结梳理出来的一些常用SQL性能优化方法,主要从四个方面(关联慢、表扫描慢、聚合慢、不可向量化)来分析,前两篇分别介绍了关联慢与表扫描慢两部分内容,本篇主要介绍剩下的两部分内容:聚合慢、不可向量化

本篇重点介绍剩下的两部分:聚合慢+SQL未向量化执行。
image.png

三、聚合慢

1、聚合倾斜情况下开启聚合重分布增强

业务问题

SQL语句执行慢,查看语句执行计划,发现性能瓶颈位于聚合处

分析思路

具体案例待补充

2、调整聚合计划以提高聚合性能

业务问题

SQL语句执行计划为

Vector Hash Aggregate
  Vector Streaming(type: REDISTRIBUTE)
    Vector Hash Aggregate

执行时间在最下边这一层Vector Hash Aggregate耗时过多且聚合后行数减少程度不大

分析思路

如下图所示,查看SQL语句执行计划

该语句hint best_agg_plan = 3,采用了hashagg+redistribute+hashagg的方法。然而,id=7那一层Hash Aggregate并没有降低30%以上的数据量,并且存在耗时过长的效果,影响sql语句执行性能,即:id=7 Hash Aggregate多余
利用hint对SQL语句进行改写,使得语句走hash+redistribute+hash的执行计划。

 /*+set global (best_agg_plan 2)*/

改动后的语句执行计划如下所示:

可以看出,少了一层Hash Aggregate提高了语句的执行效率,运行时间从300s+降低到了200s左右

小结

  • best_agg_plan = 2
    采用方法:
Vector Hash Aggregate
   Vector Streaming(type: REDISTRIBUTE)
  • best_agg_plan = 3
    采用方法:
Vector Hash Aggregate
   Vector Streaming(type: REDISTRIBUTE)
      Vector Hash Aggregate

其中,best_agg_plan = 2适用于DN一次聚集后行数缩减不明显的场景,这时可以以所有数据重分布的代价,省略DN的一次聚集操作。而best_agg_plan = 3适用于DN一次聚集后行数缩减明显的场景

总结

SQL语句聚合慢一般就是上述三种情况:当聚合列过多且不包含分布列时可以开启;可以通过调整不同best_agg_plan来选择最高效的聚合计划;一般情况下,出现sort+groupagg都会降低语句执行性能,此时可以利用guc参数进行调整。

四、查询不可向量化

业务问题

SQL语句执行过程中,存在未向量化执行的情况,影响SQL语句执行效率。

分析思路

补充

  • 技术背景
    在大宽表,数据量比较大、查询经常关注某些列的场景中,行存储引擎查询性能比较差。例如气象局的场景,单表有200~800个列,查询经常访问10个列,在类似这样的场景下,向量化执行技术和列存储引擎可以极大的提升性能和减少存储空间。
  • 向量化执行
    image.png
    标准的迭代器模型如图所示。控制流向下(下图实线)、数据流向上(下图虚线)、上层驱动下层(上层节点调用下层节点要数据)、一次一元组(下层节点每次只返回一条元组给上层节点)。
    而向量化执行相对于传统的执行模式改变是对于一次一元组的模型修改为一次一批元组,配合列存特性,可以带来巨大的性能提升。
  • 未向量化执行原因
    1. 存在行存表
    2. 存在不可向量化函数
      针对这三种情况,进行分析解决

1、行存表改列存(或开启enable_force_vector_engine)

这种情况是比较简单的,识别出来SQL语句中是否存在行存表,存在的话如果允许就将其改为列存表,否则就利用hint 来保证向量化执行

/*+set global(enable_force_vector_engine on)*/

原始SQL语句

SELECT  /*+ broadcast(bl)*/
      BSI.ORGANIZATION_CODE
      ,BSI.ITEM_CODE
      ,BSI.SUBINVENTORY_CODE 
      ,BSI.CREATED_BY        AS SUBINV_CREATED_ID  
      ,null subinv_created_name
      ,BSI.CREATION_DATE     AS SUBINV_CREATION_DATE  
      ,BIL.LOCATOR_ID  
      ,BIL.LOCATOR_CODE  
      ,BL.DESCRIPTION        AS LOCATOR_DESCRIPTION  
      ,BIL.CREATED_BY        AS LOCATOR_CREATED_ID  
      ,NULL locator_created_name
      ,BIL.CREATION_DATE     AS LOCATOR_CREATION_DATE  
      ,BSI.LAST_UPDATE_DATE AS LAST_MODIFIED_DATE
  FROM sdimfg.ogg_bas_item_sub_inventor_8656 BSI	--SDI.OGG_BAS_ITEM_SUB_INVENTOR_8656 BSI
      ,rtdwrsipa.IPA_ITEM_LOCATOR_ALL_TMP	T		--RT_ISCP_IPA.IPA_ITEM_LOCATOR_ALL_TMP T
      ,sdimfg.ogg_bas_item_locators_t_8656 BIL		--SDI.OGG_BAS_ITEM_LOCATORS_T_8656   BIL
      ,sdimfg.ogg_bas_locators_t_8656 BL			--SDI.OGG_BAS_LOCATORS_T_8656        BL
  WHERE BSI.ITEM_CODE =T.ITEM_CODE 
   AND BSI.ORGANIZATION_CODE = T.ORGANIZATION_CODE
   AND BSI.ITEM_CODE = BIL.ITEM_CODE(+)
   AND BSI.ORGANIZATION_CODE = BIL.ORGANIZATION_CODE(+)
   AND BSI.SUBINVENTORY_CODE = BIL.SUBINVENTORY_CODE(+)
   AND BIL.LOCATOR_ID = BL.LOCATOR_ID(+)

image.png
原始SQL语句的执行计划如上图所示,可以看出,该语句并未向量化执行,这会影响性能。
针对该SQL语句进行分析,发现是表rtdwrsipa.ipa_item_locator_all_tmp为行存表,因此可以使用hint强制向量化执行,优化后SQL语句如下所示:

SELECT  /*+ broadcast(bl) set global(enable_force_vector_engine on)*/
      BSI.ORGANIZATION_CODE
      ,BSI.ITEM_CODE
      ,BSI.SUBINVENTORY_CODE 
      ,BSI.CREATED_BY        AS SUBINV_CREATED_ID  
      ,null subinv_created_name
      ,BSI.CREATION_DATE     AS SUBINV_CREATION_DATE  
      ,BIL.LOCATOR_ID  
      ,BIL.LOCATOR_CODE  
      ,BL.DESCRIPTION        AS LOCATOR_DESCRIPTION  
      ,BIL.CREATED_BY        AS LOCATOR_CREATED_ID  
      ,NULL locator_created_name
      ,BIL.CREATION_DATE     AS LOCATOR_CREATION_DATE  
      ,BSI.LAST_UPDATE_DATE AS LAST_MODIFIED_DATE
  FROM sdimfg.ogg_bas_item_sub_inventor_8656 BSI	--SDI.OGG_BAS_ITEM_SUB_INVENTOR_8656 BSI
      ,rtdwrsipa.IPA_ITEM_LOCATOR_ALL_TMP	T		--RT_ISCP_IPA.IPA_ITEM_LOCATOR_ALL_TMP T
      ,sdimfg.ogg_bas_item_locators_t_8656 BIL		--SDI.OGG_BAS_ITEM_LOCATORS_T_8656   BIL
      ,sdimfg.ogg_bas_locators_t_8656 BL			--SDI.OGG_BAS_LOCATORS_T_8656        BL
  WHERE BSI.ITEM_CODE =T.ITEM_CODE 
   AND BSI.ORGANIZATION_CODE = T.ORGANIZATION_CODE
   AND BSI.ITEM_CODE = BIL.ITEM_CODE(+)
   AND BSI.ORGANIZATION_CODE = BIL.ORGANIZATION_CODE(+)
   AND BSI.SUBINVENTORY_CODE = BIL.SUBINVENTORY_CODE(+)
   AND BIL.LOCATOR_ID = BL.LOCATOR_ID(+)

image.png
优化后可以看出,SQL语句向量化执行,时间降低为88s+。

2、替换不可向量化函数(或者利用临时表降低影响范围)

原始SQL语句的执行计划如下图所示,可以看出,该语句并未向量化执行,这会影响性能。
image.png
首先使用guc参数 set enable_force_vector_engine = on;发现并未生效,SQL仍未向量化执行,证明该语句中并不存在行存表,此时可以判断为存在不可向量化函数。对SQL中的函数进行识别与排查,最后排查出存在问题的函数为:string_agg(…order by…)
对于不可向量化的函数可以采用替换函数或者落临时表来减少影响,由于该函数并不能替代,因此对于该SQL采用落临时表来降低不可向量化范围。
image.png
image.png
从上图的执行计划中可以看出,落临时表降低不可向量化范围后,执行时间由原来的42s+减少为6s+,大大提升了执行性能。

总结

**传统的pipeline执行模式:**一次一tuple。CPU大部分处理在遍历Plan Tree过程,而不是真正处理数据,CPU有效利用率低。
**改造想法:**一次一列。
针对列存数据,如果只有行引擎,通常需要将列数据重构成元组tuple给执行引擎逐行处理。Tuple deform过程影响列存数据查询处理的性能。
此时,向量化执行引擎作为打开OLAP性能之门的金钥匙之一应运而生。
**向量计算:**一次计算多个值,减少函数调用,上下文切换,尽量利用CPU的缓存以及向量化执行指令提高性能。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。