
# 查看数据倾斜状态
#### 操作场景
数据倾斜会造成查询表性能下降。对于记录数超过千万条的表，建议在执行全量数据导入前，先导入部分数据，以进行数据倾斜检查和调整分布列，避免导入大量数据后发现数据倾斜，调整成本高。
#### 背景信息
DWS是采用Shared-nothing架构的MPP（Massive Parallel Processor，大规模并发处理）系统，采用水平分布的方式，将业务数据表的元组按合适的分布策略分散存储在所有的DN。
当前产品支持复制（Replication）、散列（Hash）和轮询（Roundrobin）三种用户表分布策略。
- Replication方式：在每一个DN上存储一份全量表数据。对于数据量比较小的表建议采取Replication分布策略。
- Hash方式：采用这种分布方式，需要为用户表指定一个分布列（distribute key）。当插入一条记录时，系统会根据分布列的值进行Hash运算后，将数据存储在对应的DN中。对于数据量比较大的表建议采取Hash分布策略。
- Roundrobin方式：表的每一行被轮番地发送给各个DN，因此数据会被均匀地分布在各个DN中。对于数据量比较大的表，如果Hash分布找不到一个合适的分布列，建议采用Roundrobin分布策略。
 
对于Hash分布策略，如果分布列选择不当，可能导致数据倾斜。因此在采用Hash分布策略之后会对用户表的数据进行数据倾斜性检查，以确保数据在各个DN上是均匀分布的。一般情况下分布列都是选择键值重复度小，数据分布比较均匀的列。
#### 操作步骤
1. 分析数据源特征，选择若干个键值重复度小，数据分布比较均匀的备选分布列。
2. 从[步骤1]中选择一个备选分布列创建目标表。
   
   ```
   CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXISTS ] table_name 
       ({ column_name data_type [ compress_mode ] [ COLLATE collation ] [ column_constraint [ ... ] ]
       | table_constraint    | LIKE source_table [ like_option [...] ] }
       [, ... ])    [ WITH ( {storage_parameter = value} [, ... ] ) ]
       [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
       [ COMPRESS | NOCOMPRESS ]    [ TABLESPACE tablespace_name ]
       [ DISTRIBUTE BY { REPLICATION 
                       | ROUNDROBIN
                       | { HASH ( column_name [,...] ) } } ];
   ```
   
   
3. 参照前面章节中的办法向目标表中导入小批量数据。
   
   对于单个数据源文件，在导入时，可通过均匀切割，导入部分切割后的数据源文件来验证数据倾斜性。
   
   
4. 检验数据倾斜性。命令中的table_name ，请填入实际的目标表名。
   
   ```
   SELECT a.count,b.node_name FROM (SELECT count(*) AS count,xc_node_id FROM table_name GROUP BY xc_node_id) a, pgxc_node b WHERE a.xc_node_id=b.node_id ORDER BY a.count desc;
   ```
   
   
5. 若各DN上数据分布差小于10%，表明数据分布均衡，选择的分布列合适。请清理已导入小批量数据，导入全量数据，以完成数据迁移。
   
   若各DN上数据分布差大于等于10%，表明数据分布倾斜，请从[步骤1]的备选分布列中删除该列，删除目标表，并重复[步骤2] 、[步骤3] 、[步骤4] 和[步骤5]。
   ![](https://support.huaweicloud.com/migration-dws/public_sys-resources/note_3.0-zh-cn.png)
   此处的数据分布差表示实际查询到DN上的数据量与DN平均数据量的差异。分布差可以通过视图[PGXC_GET_TABLE_SKEWNESS](https://support.huaweicloud.com/devg-dws/dws_04_0805.html)查看。
   
   
6. （可选）如果上述步骤不能选出适合的分布列，需要从备选分布列选择多个列的组合作为分布列来完成数据迁移。
 
#### 示例
对目标表staffs选择合适的分布列。
1. 分析表staffs的数据源特征，选择数据重复度低且分布均匀的备选分布列staff_ID、FIRST_NAME和LAST_NAME。
2. 先选择staff_ID作为分布列，创建目标表staffs。
   ```
   CREATE TABLE staffs
   (
     staff_ID       NUMBER(6) not null,
     FIRST_NAME     VARCHAR2(20),
     LAST_NAME      VARCHAR2(25),
     EMAIL          VARCHAR2(25),
     PHONE_NUMBER   VARCHAR2(20),
     HIRE_DATE      DATE,
     employment_ID  VARCHAR2(10),
     SALARY         NUMBER(8,2),
     COMMISSION_PCT NUMBER(2,2),
     MANAGER_ID     NUMBER(6),
     section_ID     NUMBER(4)
   )  
   DISTRIBUTE BY hash(staff_ID);
   ```
   
3. 向目标表staffs中导入部分数据。
   根据以下查询所得，集群环境中主DN数为8个，则建议导入的记录数为80000条。
   ```
   SELECT count(*) FROM pgxc_node where node_type='D';
    count 
   -------
        8
   (1 row)
   ```
   
4. 校验以staff_ID为分布列的目标表staffs的数据倾斜性。
   ```
   SELECT a.count,b.node_name FROM (select count(*) as count,xc_node_id FROM staffs GROUP BY xc_node_id) a, pgxc_node b WHERE a.xc_node_id=b.node_id ORDER BY a.count desc;
   count | node_name
   ------+-----------
   11010 | datanode4
   10000 | datanode3
   12001 | datanode2
    8995 | datanode1
   10000 | datanode5
    7999 | datanode6
    9995 | datanode7
   10000 | datanode8
   (8 rows)
   ```
   
5. 根据上一步骤查询所得，各DN上数据分布差大于10%，数据分布倾斜。所以从步骤1的备选分布列中删除该列，并删除目标表staffs。
   ```
   DROP TABLE staffs;
   ```
   
6. 尝试选择staff_ID、FIRST_NAME和LAST_NAME的组合作为分布列，创建目标表staffs。
   ```
   CREATE TABLE staffs
   (  
     staff_ID       NUMBER(6) not null,
     FIRST_NAME     VARCHAR2(20),
     LAST_NAME      VARCHAR2(25),
     EMAIL          VARCHAR2(25),
     PHONE_NUMBER   VARCHAR2(20),
     HIRE_DATE      DATE,
     employment_ID  VARCHAR2(10),
     SALARY         NUMBER(8,2),
     COMMISSION_PCT NUMBER(2,2),
     MANAGER_ID     NUMBER(6),
     section_ID     NUMBER(4)
   ) 
   DISTRIBUTE BY hash(staff_ID,FIRST_NAME,LAST_NAME);
   ```
   
7. 校验以staff_ID、FIRST_NAME和LAST_NAME的组合为分布列的目标表staffs的数据倾斜性。
   ```
   SELECT a.count,b.node_name FROM (select count(*) as count,xc_node_id FROM staffs GROUP BY xc_node_id) a, pgxc_node b WHERE a.xc_node_id=b.node_id ORDER BY a.count desc;
   count | node_name
   ------+-----------
   10010 | datanode4
   10000 | datanode3
   10001 | datanode2
    9995 | datanode1
   10000 | datanode5
    9999 | datanode6
    9995 | datanode7
   10000 | datanode8
   (8 rows)
   ```
   
8. 根据上一步骤查询所得，各DN上数据分布差小于10%，数据分布均衡，选择的分布列合适。
9. 清理已导入小批量数据。
   ```
   TRUNCATE TABLE staffs;
   ```
   
10. 导入全量数据，以完成数据迁移。
 
