摘要:路径生成是表关联方式确定的主要阶段,本文介绍了几个影响路径生成的要素:cost_param, scan方式,join方式,stream方式,并从原理上分析如何干预路径的生成。

一、cost模型选择

顾名思义,cost_param是控制cost相关的一个参数。在了解cost_param之前,先回顾一下选择率的概念,GaussDB优化器中的选择率是指,当一个表有一个过滤或关联条件时,通过该条件能被选中的行数占总行数的比例,是介于0~1之间的一个实数。选择率在优化器中是一个重要的概念,主要应用于行数和distinct值的估算,行数和distinct值是计划生成中的基本要素。

首先,我们来看带有过滤条件的基表行数如何估算。如果一个表只有一个过滤条件,那么以选择率乘以表的行数,即可得到过滤完的行数;如果有多个过滤条件,那么就需要算出一个综合的选择率,如何计算?方式有二:一是通过多列统计信息直接计算,二是通过组合单列的选择率。那么组合的方式就由参数cost_param决定了,具体地,

举一个例子,TPC-H 1x的part表,过滤条件是:p_brand = 'Brand#45' and p_container = 'WRAP CASE',查看不同cost_param下的过滤后行数。

(1)cost_param=0

(2)cost_param=2

从估算出的行数(E-rows)和实际的行数(A-rows)对比可以看出,cost_param=0的不相关模型适合part表的p_brand和p_container列。

其次,Join的行数怎么估算的呢?原理跟过滤条件的行数估算是类似的,如果没有多列统计信息可以使用,则也需要单独计算每个条件的选择率,然后计算出综合选择率,得出行数。例如 TPC-H 1x lineitem和orders关联,关联条件是:l_orderkey = o_orderkey and o_custkey = l_suppkey,不同cost_param的执行情况如下:

(1)cost_param=0

(2)cost_param=2

此例中,Join的列之间也适合完全相关模型,这与l_orderkey和l_suppkey的分布是吻合的。

由于TPC-H的模型接近完全不相关模型,因此cost_param=0模型可以较好的描述场景,实际应用中,用户可以根据具体业务场景来调整模型,行数估算的准确性是计划生成的重要保证,在调优中检查估算的最直接的地方。GaussDB会在后续版本中新增更多的模型供业务需求选择。

二、Scan方式的选择

GaussDB中扫描方式主要分顺序扫描和索引扫描,每种扫描方式都对应若干扫描算子,顺序扫描在行列存中对应的扫描算子分别是Seq Scan和CStore Scan算子(下面我们讨论中不加区分)。这些扫描算子大部分都可以通过开关来进行调控,例如Seq Scan,如果设置enable_seqscan=off,则表示不会优先选择Seq Scan,而不是一定不会选。扫描方式的选择,很大程度上决定了获取基表数据的路径。我们以如下的例子来说明:

select l_orderkey, o_custkey from lineitem, orders where l_orderkey = o_orderkey;

lineitem分布键是l_orderkey,并且在l_orderkey上有index,orders分布键是o_orderkey。默认情况下,Scan的方式如下:

两个表都是顺序扫描的路径,关联方式选择了Hash Join。如果把Seq Scan关掉(enable_seqscan=off),计划如下:

lineitem的扫描变成了Index Only Scan(因为l_orderkey的类型是int),而在orders表上仍然选择Seq Scan(因为没有其他路径),同时关联方式也变为了Nest Loop,因为Hash Join需要全表扫描数据(lineitem的Seq Scan已经被关掉了)。优化器的选择方式我们从代价(E-costs)一栏中也可以看出。再把Index Only Scan关掉,看看计划如何变化:

扫描路径都变为了Seq Scan,而且Seq Scan的代价都很大。此时既然都走了Seq Scan,为什么不选Hash Join呢,把Nest Loop关掉,看看Hash Join计划的代价:

从代价上看出Hash Join的总代价比Nest Loop的小,但优化器没有选择Hash Join,这是因为优化器比较路径代价时,会比较Startup和Total代价,即启动代价和总代价,综合考虑,E-costs栏中显示的是总代价。把explain_perf_mode设置为normal,查看原Nest Loop的启动代价:

红框中的两个cost,分别是启动代价和总代价,在看Hash Join的cost,明显Hash Join的启动代价比Nest Loop的大很多(启动代价代表了输出第一条数据的代价),优化器在比较路径时,综合了这两个代价,最终推荐了Nest Loop的路径。

从上面的例子可以看出,扫描路径的调控,可以改变路径生成,合理的搭配是生成最优计划的前提,默认情况下,GaussDB优化器可以根据现有的路径选择(如上面的lineitem有两条扫描路径,orders只有一条扫描路径),最后确定出最优的一条。两条路径代价比较时,总代价不是唯一要素,但总代价越小,一般也会越容易被选中。

三、关联方式的选择

GaussDB优化器中表关联的主要方式有:Nest Loop,Hash Join和Merge Join,分别可以通过enable_nestloop、enable_hashjoin、enable_mergejoin进行控制,这种控制也不是绝对的,可以理解为是否优先选择。大部分场景下,三种路径的代价关系:Hash Join < Merge Join < Nest Loop。我们以一个简单的关联示例说明,store_returns和store_sales是TPC-DS 1x中两个表,SQL如下:

select count(*) from store_returns, store_sales where sr_customer_sk = ss_customer_sk;

默认情况下,优化器推荐Hash Join路径,计划如下:

如果把Hash Join关掉,则优化器选择了Merge Join路径:

如果再把Merge Join路径关掉,可能就会选择Nest Loop路径。关联方式的控制开关一般用于调优或规避问题,但具体是否能够起作用要看具体的语句,除了当前关联方式,还有没有其他方式。实际场景中,一个语句中关联的算子较多,一般很难用参数enable_hashjoin或enable_nestloop或enable_mergejoin来控制某两个表的Join方式,GaussDB中更细致的语句级别的调优手段是Plan Hint,感兴趣的读者可以参考产品手册。

四、Stream方式的选择

Stream算子是GaussDB分布式执行的关键算子之一,主要起到网络传输的作用,概要介绍可以参考:GaussDB(DWS)性能调优系列实战篇一:十八般武艺之总体调优策略。Stream算子由参数enable_stream_operator控制,如果关掉Stream算子,则可能导致生成不下推的计划,例如:

因为lineitem表关联的键l_partkey不是lineitem的分布键,需要添加Stream算子,但Stream功能被禁,于是只能生成不下推计划。

GaussDB计划中常见的主要Stream算子包括Redistribute、Broadcast和Gather。Gather一般是分布式计划中,CN用于收集DN的数据进行最后的处理,除非最后收集的行数非常多,这个算子涉及性能问题一般较少。Redistribute和Broadcast一是对“互补”的算子,前者用于重分布,后者用于广播,生成计划时,优化器会根据代价大小来选择。当Join Key没有包含表的分布键的时候,一般会添加Redistribute路径,能选择Redistribute路径理论上也可选择Broadcast路径,最终选择哪条路径要看优化器估算的代价是多少。这两个算子可以通过参数enable_redistribute和enable_broadcast进行控制。

在SMP开启的情况下,当并行度(dop)大于1时,一般还会有Local Redistribute、Split Redistribute、Local Broadcast和Split Broadcast;当倾斜优化开启时,还有PART REDISTRIBUTE PART ROUNDROBIN、PART_REDISTRIBUTE_PART_BROADCAST、PART_REDISTERIBUTE_PART_LOCAL等等,这些也是Stream算子,主要就是重分布、广播、RoundRobin的一些扩展形式,这里我们不一一介绍了,感兴趣的读者可以参考GaussDB DWS 产品手册。

我们考虑两个表的简单关联,store_sales和sr_tbl,它们的分布键分别是ss_item_sk 和sr_returned_date_sk,Join 条件是store_sales.ss_customer_sk =sr_tbl. sr_customer_sk,执行结果如下:

由于两个表的分布键都不是Join Key,因此走Hash Join路径的话需要有一个表做Broadcast或者两个表都做Redistribute,但是store_sales表比较大(E-rows显示28.7亿行),而sr_tbl表行数估算比较少(E-rows显示100行),优化器认为适合做Broadcast。于是最终选择了一边Broadcast的计划。

对于这个计划,由于sr_tbl表统计信息不准确(如果是中间结果集,则表示中间结果集估算不准),一种调优的方法是,将sr_tbl的表统计信息重新收集准确一些(如果sr_tbl是中间结果集,则无法收集),另一种方法是让sr_tbl走Redistribute路径,而后者我们又有两种方式来实现,一是用Plan Hint,即在生成计划时,告诉优化器走Redistribute路径,二是把Broadcast关掉。禁用Broadcast后,执行计划如下:

本列中,开启了SMP自适应,即优化器会根据系统资源和当前Active SQL数量来自行决定并行度(dop),如果Redistribute和Broadcast选择不当,则可能导致

(1)Broadcast计划会出现下盘

(2)两个计划的并行度不一样,最终执行时间可能会差异比较大。

对于Stream方式的控制,一般的调优方式有Plan Hint、GUC参数、改善统计信息或估算信息。

五、结束语

本文介绍的cost_param属于cost底层参数,建议对数据特征和使用场景比较熟悉的DBA慎重使用。Scan、Join、Stream调控的基本依据也是代价,代价一般体现在执行耗时上,调优时可从Performance中识别出性能的瓶颈点,分析选择的算子是否与代价匹配。另外,除了本文介绍的Session级别的控制参数外,还有基表、中间结果的行数,也可以通过Plan Hint进行语句级别的调控,感兴趣读者可通过GaussDB DWS产品文档进一步了解。

本文分享自华为云社区《GaussDB(DWS)性能调优系列实战篇五:十八般武艺之路径干预》,原文作者:- 大道至简 - 。

点击关注,第一时间了解华为云新鲜技术~

十八般武艺玩转GaussDB(DWS)性能调优:路径干预的更多相关文章

  1. JVM 性能调优实战之:一次系统性能瓶颈的寻找过程

    玩过性能优化的朋友都清楚,性能优化的关键并不在于怎么进行优化,而在于怎么找到当前系统的性能瓶颈.性能优化分为好几个层次,比如系统层次.算法层次.代码层次…JVM 的性能优化被认为是底层优化,门槛较高, ...

  2. MySQL性能调优与架构设计——第 15 章 可扩展性设计之Cache与Search的利用

    第 15 章 可扩展性设计之Cache与Search的利用 前言: 前面章节部分所分析的可扩展架构方案,基本上都是围绕在数据库自身来进行的,这样是否会使我们在寻求扩展性之路的思维受到“禁锢”,无法更为 ...

  3. sql server性能调优

    转自:https://www.cnblogs.com/woodytu/tag/%E6%80%A7%E8%83%BD%E8%B0%83%E4%BC%98%E5%9F%B9%E8%AE%AD/defaul ...

  4. 大厂运维必备技能:PB级数据仓库性能调优

    摘要:众所周知,数据量大了之后,性能是大家关注的一点,所以我们在业务开发的时候,特别关注性能,做为一个架构师,必须对性能要了解,要懂.才能设计出高性能的业务系统. 一.GaussDB分布式架构 所谓集 ...

  5. web前端性能调优

    最近2个月一直在做手机端和电视端开发,开发的过程遇到过各种坑.弄到快元旦了,终于把上线了.2个月干下来满满的的辛苦,没有那么忙了自己准备把前端的性能调优总结以下,以方便以后自己再次使用到的时候得于得心 ...

  6. [网站性能2]Asp.net平台下网站性能调优的实战方案

    文章来源:http://www.cnblogs.com/dingjie08/archive/2009/11/10/1599929.html 前言    最近帮朋友运营的平台进行了性能调优,效果还不错, ...

  7. Asp.net平台下网站性能调优的实战方案(转)

    转载地址:http://www.cnblogs.com/chenkai/archive/2009/11/07/1597795.html 前言 最近帮朋友运营的平台进行了性能调优,效果还不错,所以写出来 ...

  8. 第0/24周 SQL Server 性能调优培训引言

    大家好,这是我在博客园写的第一篇博文,之所以要开这个博客,是我对MS SQL技术学习的一个兴趣记录. 作为计算机专业毕业的人,自己对技术的掌握总是觉得很肤浅,博而不专,到现在我才发现自己的兴趣所在,于 ...

  9. sqlserver性能调优第一步

    相信不少的朋友,无论是做开发.架构的,还是DBA等,都经常听说“调优”这个词.说起“调优”,可能会让很多技术人员心头激情澎湃,也可能会让很多人感觉苦恼,不知道如何入手.当然,也有很多人对此不屑一顾,因 ...

  10. JavaScript:内存泄露、性能调优

    1.在进行JS内存泄露检查之前,先要了解JS的内存管理: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Manageme ...

随机推荐

  1. SAP(ABAP) 显示等待图标的FM:SAPGUI_PROGRESS_INDICATOR-SAP进度条

    在执行一些数据量大的报表时候,为了防止用户认为是死机,可以再程序中添加正在处理的图标,可以CALL一个 FM来实现. CALL FUNCTION 'SAPGUI_PROGRESS_INDICATOR' ...

  2. Samba服务器搭建配置

    本次环境: 服务端-centos6.8-192.168.2.200 客户端1-centos6.8-192.168.2.201 客户端2-Windows7-192.168.2.104 假设条件如下: 使 ...

  3. ubuntu14.04服务版/etc/init.d/smbd restart无效的解决方法

    刚装的ubuntu14.04配置完smbd发现service或者/etc/init.d/smbd restart都不显示任何输出,也没起作用 echo $?输出1,查看脚本发现 if init_is_ ...

  4. ESLint 检查代码质量

    利用 ESLint 检查代码质量 其实很早的时候就想尝试 ESLint 了,但是很多次都是玩了一下就觉得这东西巨复杂,一执行检查就是满屏的error,简直是不堪入目,遂放弃.直到某天终于下定决心深入看 ...

  5. C#部分---利用arraylist集合做滚动抽奖;

    输入多个手机号码,放到集合中,进行三秒钟的滚动抽奖:随机显示号码,清空,再显示: 1.收集号码: 2.每隔三秒进行抽奖,及作弊代码,哈哈哈: 3.System.Threading.Thread.Sle ...

  6. Hash算法原理理解

    我们有很多的小猪,每个的体重都不一样,假设体重分布比较平均(我们考虑到公斤级别),我们按照体重来分,划分成100个小猪圈. 然后把每个小猪,按照体重赶进各自的猪圈里,记录档案. 好了,如果我们要找某个 ...

  7. Java内存溢出异常(下)

    此篇是上一篇文章Java内存溢出异常(上)的续篇,没有看过的同学,可以先看一下上篇.本篇文章将介绍剩余的两个溢出异常:方法区和运行时常量池溢出. 方法区和运行时常量池溢出 这部分为什么会放在一起呢?在 ...

  8. poj2385 Apple Catching(dp状态转移方程推导)

    https://vjudge.net/problem/POJ-2385 猛刷简单dp的第一天的第一题. 状态:dp[i][j]表示第i秒移动j次所得的最大苹果数.关键要想到移动j次,根据j的奇偶判断人 ...

  9. 框架模式MVC在安卓中的实践

    我们采用ListView来演示我们的MVC模式,目录结构: 实体类:包含了书的名字和图片信息 public class Book { //书名 private String name; //书的图片 ...

  10. 进度条QProgressBar

    import sys from PyQt5.QtCore import Qt, QTimer from PyQt5.QtWidgets import QApplication, QWidget, QP ...