【DWS】MPP架构下数据倾斜率分析

举报
wzhyalfa 发表于 2020/06/12 19:21:18 2020/06/12
【摘要】 MPP架构下数据倾斜率分析方法阐述,及指导应用到实际生产服务中。

MPP架构下数据倾斜率分析

 

MPP架构下处理海量数据,需要各位参与者时刻关注并行处理能力,若无法发挥并行能力,再大的集群也无法发挥其处理能力,可能还会出现用户质疑集群处理能力。作为数据库使用者,特别是高阶使用人员、运维监控人员,需要即时发现系统隐患。

 

本文是从数据表的数据分布角度探讨,发现有害倾斜,优化系统表数据分布。

 

1.    涉及到的检索手段有:

a)      表空间大小占用角度出发分析:table_distribution()

b)     表数据记录行数角度出发分析:table_skewness('schema.table')

 

2.       倾斜率计算方法说明:

a)         方法一: (最大值-最小值)/合计值

b)         方法二:1-(平均值/最大值)

  这两种计算方式,倾斜率最大值不超过1,即小于等于100%,特别是方法二永远达不到100%值。

c)         两种方法跟踪比对:

--跟踪倾斜率

select schemaname,tablename

,(100-100*avg(dnsize)/nullif(max(dnsize),0))::numeric(5,2) "New_Skew(%)"

,(max(dnsize)-min(dnsize)) skewsize

,(((max(dnsize)-min(dnsize))/sum(dnsize))*100)::numeric(6,3) skewratio

,stddev(dnsize)::numeric(1000,0) skewstddev

from table_distribution('public','wzy_rows') a

group by 1,2 order by desc;

 

跟踪如下,

     image.png

 

d)         对比个人倾向结论

即使用方法二“1-(平均值/最大值) “跟踪倾斜率;

 

3.       倾斜引起空间浪费计算说明:

a)         理念

鉴于MPP架构下希望所有数据表尽量均衡分布,即整个系统是处于分布平均的情况下,跟踪当前表对系统均衡性的影响分析。

b)         计算方式

最大值*DN总数-当前合计值

Select schemaname,tablename,

(100-100*avg(dnsize)/nullif(max(dnsize),0))::numeric(5,2)   "New_Skew(%)"

,max(dnsize)*count(1)-sum(dnsize)   "WastedPerm(B)"

From   table_distribution('public','wzy_rows') a

group   by 1,2 order by 3 desc;

 

4.       倾斜率选择使用空间占用还是记录数占用计算问题

a)         空间问题

当前涉及page8KB预占问题,即并不是每新增一条记录就带来空间线性增长;即空间占用大小差不多,但可能记录数存在较大较别,当该数据进行关联运算时,会存在计算资源占用不一致,发生倾斜场景;

b)         记录数问题

若只关注记录数,无法准确反映在数据重分布过程中的IO变化,存储工作空间变化;

c)         结论

由于空间测算成本较记录数测算成本低,常规情况下先看空间倾斜率,再进一步关注记录倾斜情况。

 

5.       最后,生产环境数据倾斜率分析与调整

a)         全系统的偷懒方式查询

select * from

(

select   schemaname,tablename,(100-100*avg(dnsize)/nullif(max(dnsize),0))::numeric(5,2)   Skew

,max(dnsize)*count(1)-sum(dnsize)   WastedPerm

,Table_RowSkew(schemaname||'.'||tablename)   as Row_Skew

 From table_distribution() a   group by 1,2

having Skew>30 ) 

where Row_Skew>30 order by WastedPerm desc

即从浪费空间(WastedPerm)最多的表开始排查问题。

b)         精细排查

--提取表名

/* (可选)

空间分布:

select * from table_distribution('db1','tb1');

记录分布:

select * from table_skewness('db1.tb1');

*/

--1.查看表字段信息

Select pg_get_tabledef('db1.tb1');

--

select tbl.relname,col.attname,col.attnum

from pg_attribute col

inner JOIN pg_class tbl

ON col.attrelid = tbl.oid

where col.attnum>0

and tbl.oid='db1.tb1'::regclass

;

--2.重新选择分布列,查看记录倾斜情况

with tmp as (

select * from table_skewness('db1.tb1','colA,ColB')

)

select tmp.*,b.skew::text||'%' skew

from tmp,

(select (100-100*(avg(num::bigint)/max(num::bigint)))

  ::dec(5,2) skew

  from tmp ) b

;

--3.重建表

create table db1.tmp_tb1 DISTRIBUTE BY HASH (colA,colB)

as table db1.tb1  with data;

--4.验证空间倾斜情况

with tmp as (

select * from table_distribution('db1','tb1')

)

select tmp.*,b.skew::text||'%' skew

from tmp,

(select (100-100*(avg(dnsize)/max(dnsize)))

  ::dec(5,2) skew

  from tmp ) b

;

--5.对换表名,旧名事后或人工或程序化删除

alter table db1.tb1 rename to tmp_tb1_20200612;

alter table db1.tmp_tb1 rename to tb1;

 

         一般重新选择的分布列,除了关注倾斜率越小越好,还要从数据关联、使用角度统合考虑,不能一味追求分布的完全均匀;

 

6.      

a)         上文使用到的记录数倾斜率自定义函数table_skew(’表名‘)

CREATE OR REPLACE FUNCTION Table_RowSkew(_table_name   text )
 RETURNS numeric
 LANGUAGE plpgsql
 NOT FENCED NOT SHIPPABLE
AS $function$
DECLARE
  row_data record;
  row_name record;
  query_str text;
  query_str_nodes text;
  cnt bigint;
  total_rows bigint;
  total_cnt bigint := 0;
  max_row bigint := 0;
 
  BEGIN
        -- total records
        EXECUTE 'SELECT count(1) FROM ' ||   _table_name
                     INTO total_rows;
        IF total_rows = 0 THEN
            RETURN 0;
        END IF;
        
        --Get the node names
        query_str_nodes := 'SELECT node_name   FROM pgxc_node where node_type IN (''C'', ''D'') AND oid::text in ' ||
        '(SELECT   regexp_split_to_table(nodeoids::text, '' '') FROM pgxc_class WHERE   pcrelid=''' || _table_name || '''::regclass::oid)';
 
        FOR row_name IN   EXECUTE(query_str_nodes) LOOP
            query_str := 'EXECUTE DIRECT ON   (' || row_name.node_name || ') ''select count(1) as count1 from ' || $1 ||   '''';
            
            EXECUTE(query_str) INTO cnt;
            IF max_row < cnt THEN
                max_row := cnt;
            END IF;
            total_cnt := total_cnt + 1;
        END LOOP;
 
            RETURN 100 - 100 * (total_rows/total_cnt)/max_row;
         END; $function$


 


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

评论(0

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

全部回复

上滑加载中

设置昵称

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

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

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