摘要:门路生成是表关联形式确定的次要阶段,本文介绍了几个影响门路生成的因素: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_nestloopenable_hashjoinenable_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)性能调优系列实战篇五:十八般武艺之门路干涉》,原文作者:- 大道至简 - 。

点击关注,第一工夫理解华为云陈腐技术~