2.3 SQL 调优指南
2.3.6 典型 SQL 调优点
2.3.6.6 数据倾斜调优
数据倾斜问题是分布式架构的重要难题,它破坏了MPP架构中各个节点对等的要求,
导致单节点(倾斜节点)所存储或者计算的数据量远大于其他节点,所以会造成以下 危害:
● 存储上的倾斜会严重限制系统容量,在系统容量不饱和的情况下,由于单节点倾 斜的限制,使得整个系统容量无法继续增长。
● 计算上的倾斜会严重影响系统性能,由于倾斜节点所需要运算的数据量远大于其 它节点,导致倾斜节点降低系统整体性能。
● 数据倾斜还严重影响了MPP架构的扩展性。由于在存储或者计算时,往往会将相 同值的数据放到同一节点,因此当倾斜数据(大量数据的值相同)出现之后,即 使我们增加节点,系统瓶颈仍然受限于倾斜节点的容量或者性能。
GaussDB(for openGauss)数据库针对数据倾斜问题给出了完整的解决方案,包括存储 倾斜和计算倾斜两大问题,下面分别进行介绍。
存储层数据倾斜
GaussDB(for openGauss)数据库中,数据分布存储在各个DN上,通过分布式执行提 高查询的效率。但是,如果数据分布存在倾斜,则会导致分布式执行某些DN成为瓶
颈,影响查询性能。这种情况通常是由于分布列选择不合理,可以通过调整分布列的 方式解决。
例如下例:
postgres=# explain performance select count(*) from inventory;
5 --CStore Scan on lmz.inventory
dn_6001_6002 (actual time=0.444..83.127 rows=42000000 loops=1) dn_6003_6004 (actual time=0.512..63.554 rows=27000000 loops=1) dn_6005_6006 (actual time=0.722..99.033 rows=45000000 loops=1) dn_6007_6008 (actual time=0.529..100.379 rows=51000000 loops=1) dn_6009_6010 (actual time=0.382..71.341 rows=36000000 loops=1) dn_6011_6012 (actual time=0.547..100.274 rows=51000000 loops=1) dn_6013_6014 (actual time=0.596..118.289 rows=60000000 loops=1) dn_6015_6016 (actual time=1.057..132.346 rows=63000000 loops=1) dn_6017_6018 (actual time=0.940..110.310 rows=54000000 loops=1) dn_6019_6020 (actual time=0.231..41.198 rows=21000000 loops=1) dn_6021_6022 (actual time=0.927..114.538 rows=54000000 loops=1) dn_6023_6024 (actual time=0.637..118.385 rows=60000000 loops=1) dn_6025_6026 (actual time=0.288..32.240 rows=15000000 loops=1) dn_6027_6028 (actual time=0.566..118.096 rows=60000000 loops=1) dn_6029_6030 (actual time=0.423..82.913 rows=42000000 loops=1) dn_6031_6032 (actual time=0.395..78.103 rows=39000000 loops=1) dn_6033_6034 (actual time=0.376..51.052 rows=24000000 loops=1) dn_6035_6036 (actual time=0.569..79.463 rows=39000000 loops=1)
在performance信息中,可以看到inventory表各DN的scan行数,发现各DN的行数差 距较大,最大的为63000000,最小的只有15000000,差了4倍。这个差距对于数据扫 描的性能影响还可以接受,但如果上层有join算子,则影响较大。
通常,数据表在各DN上是hash分布的,因此分布列的选择很重要。通过
table_skewness()来查看上述inventory表在各DN的数据分布倾斜,查询结果如下:
postgres=# select table_skewness('inventory');
table_skewness (18 rows)
通过查询建表定义,可以发现,目前该表是以inv_date_sk作为分布列的,导致存在倾 斜。通过查看各列的数据分布情况,改为inv_item_sk作为分布列,则倾斜情况分布如 下:
postgres=# select table_skewness('inventory');
table_skewness
("dn_6011_6012 ",43683600,5.579%) (18 rows)
数据分布倾斜的问题得到解决。
在查询执行的过程中,join key、group by key等往往不是表的分布列,因此需要按照 join key、group by key上数据的hash值,让数据在各个DN之间进行重新分布,这个 过程对应于计划中的Redistribute算子。当重分布列上的数据存在倾斜时,就会导致运
6 --Streaming(type: REDISTRIBUTE) datanode1 (rows=5050368) datanode2 (rows=15276032) datanode3 (rows=5174272) datanode4 (rows=5219328)
和存储倾斜相比,计算倾斜更难以提前识别,因此GaussDB提出了RLBT(Runtime Load Balance Technology)方案,用以解决运行时的计算倾斜问题。RLBT方案主要分 为两个层面,第一步是计算倾斜识别,第二步是计算倾斜解决。下面分别进行介绍。
1. 倾斜识别
计算倾斜的识别,即预先识别计算过程中的重分布列是否存在倾斜数据。RLBT方 案中给出了三个解决手段,统计信息识别,hint方式指定以及规则识别:
– 统计信息识别
需要用户先执行analyze收集各表的统计信息,然后优化器能够自动利用统计
现在BI系统往往会产生大量带有outer join(left join、right join、full join)
的SQL,outer join在匹配失败的情况下会补空产生大量NULL值,如果接下 来在补空列上进行join或者group by操作,就会导致NULL值倾斜。当前RLBT 技术会自动识别这种场景,并生成相应的NULL值倾斜优化计划。 [7125.834,7472.111]
7 | -> Seq Scan on public.skew s | [1837.079,1911.025]
8 | -> Hash | [2612.484,2640.572]
9 | -> Streaming(type: PART REDISTRIBUTE PART BROADCAST) | [1193.548,1297.894]
10 | -> Seq Scan on public.test t | [314.343,328.707]
(10 rows)
5 --Vector Hash Join (6,8) Hash Cond: s.x = t.x
Skew Join Optimizated by Statistic
6 --Streaming(type: PART REDISTRIBUTE PART ROUNDROBIN) datanode1 (rows=7635968)
datanode2 (rows=7517184) datanode3 (rows=7748608) datanode4 (rows=7818240)
上述执行计划中,可以看到Skew Join Optimizated by Statistic的字样,代表该计 划为倾斜优化计划,其中Statistic关键字代表该倾斜优化来自于统计信息,除此之 group by key进行去重操作,然后再进行重分布。因为经过DN内部去重之后,从 全局来看,每个值的数量都不会超过DN数,因此不会出现严重的数据倾斜问题。
其中存在大量倾斜数据,导致数据按照group by key进行重分布之后,datanode1 的数据量是其他节点的数十万倍。在倾斜优化之后,首先在本DN进行一次group
▪
支持nest loop,merge join,hash join等join方式;▪
当倾斜数据处于join的left侧时,支持inner join,left join,semi join,anti join;当倾斜属于位于join的right侧时,支持inner join,right join,right semi join,right anti join。
▪
通过统计信息得到的倾斜优化计划,优化器会根据代价判断该计划是否 为最优计划。通过hint和规则会强制生成倾斜优化计划。– agg算子