GaussDB Hash表分布列選擇原則及數據傾斜檢測
本文轉載自微信公眾號「數據和云」,作者宋俊卓 。轉載本文請聯系數據和云公眾號。
GaussDB如果采用分布式部署模式,則可以根據數據量以及用途定義兩種不同分布方式的表,分別為復制表(Replication)和哈希(Hash)表。
復制表(Replication)是將表中的全量數據在集群的每一個DN實例上保留一份,主要適用于數據量較小的表。這種存儲方式的優點是每個DN上都有此表的全量數據,在Join操作中可以避免數據重分布操作,從而減小網絡開銷。缺點是每個DN都保留了表的完整數據,造成數據的冗余。一般情況下只有較小的維度表才會定義為Replication表。
哈希(Hash)表是將表中某一個或幾個字段進行hash運算后,生成對應的hash值,根據DN實例與哈希值的映射關系獲得該元組的目標存儲位置。對于Hash分布表,在讀/寫數據時可以利用各個節點的IO資源,大大提升表讀/寫速度。一般情況下大表定義為Hash表。
Hash分布表的分布列選取至關重要,需要滿足以下原則:
(1)列值應比較離散,以便數據能夠均勻分布到各個DN。例如,考慮選擇表的主鍵為分布列,如在人員信息表中選擇身份證號碼為分布列。
(2)在滿足第一條原則的情況下盡量不要選取存在常量filter的列。例如,表dwcjk相關的部分查詢中出現dwcjk的列zqdh存在常量的約束(例如zqdh=’000001’),那么就應當盡量不用zqdh做分布列。
(3)在滿足前兩條原則的情況下,考慮選擇查詢中的連接條件為分布列,以便Join任務能夠下推到DN中執行,且減少DN之間的通信數據量。
(4)一般不建議新增一列專門用作分布列,尤其不建議新增一列且用SEQUENCE的值來填充做為分布列,因為SEQUENCE可能會帶來性能瓶頸和不必要的維護成本。
對于Hash分布表策略,如果分布列選擇不當,可能導致數據傾斜,查詢時出現部分DN的I/O短板,從而影響整體查詢性能。因此在采用Hash分布表策略之后需對表的數據進行數據傾斜性檢查,以確保數據在各個DN上是均勻分布的。
GaussDB中提供了1個視圖pgxc_get_table_skewness,可以查詢數據庫中所有schema下的表在各個DN的分布情況以及傾斜率,雖然可以通過schemaname和tablename查詢指定表的傾斜情況,但該視圖查詢時耗時較長,僅適用于數據量較小的表(10W以下),尤其不建議不增加條件查詢所有表的數據傾斜情況。該視圖各個字段說明如下:
除此之外,可以使用函數table_skewness()和table_distribution()查詢指定表的數據傾斜情況。在使用table_skewness()時,如果不指定具體字段,默認查詢當前分布列的數據傾斜程度,則該函數可以用來評估表的其他字段分布傾斜情況。同樣,當表的數據量巨大時,這兩個函數查詢耗時都比較長。因此對于一張數據量較大的表,一般使用如下語句查詢其數據傾斜情況:
- select xc_node_id, count(1) from tablename group by xc_node_id order by xc_node_id desc;
如果需要查詢數據庫中傾斜的表,除了使用上面提到的視圖pgxc_get_table_skewness,還可以通過排查各個DN實例數據存儲目錄的大小以及數據文件來找出傾斜的表,這也是實際應用中比較常用的方法。
具體方法及步驟如下:
(1)在所有節點上執行df –h查看各個DN數據目錄使用率是否有接近,找到使用率明顯較大的磁盤目錄。
(2)通過 cm_ctl query –Cvd 確認該磁盤節點對應的DN實例(如上一步檢查為slave磁盤占用率過大,則需要查看與該備實例對應的主實例磁盤使用情況),確認DN實例端口號。可通過以下方式查詢DN實例端口號:
- select * from pgxc_node;
- 或者
- cat DN實例數據目錄/postgresql.conf |grep Port
(3)進入實例base目錄,執行du -ak | sort -nr | more查找文件大小為1GB,且文件前綴數字ID相同的文件,查找相同文件數量最多的文件,記錄其ID值及其所在文件目錄ID值。
(4)通過gsql連接DN實例,并通過文件目錄ID確認表所屬數據庫。
- select oid,* from pg_database where oid='1642599';
(5)切換至該數據庫,通過文件的ID確認表名稱,執行如下SQL:
- select relname from pg_class where relfilenode = 3308672;
(6)根據表名稱進一步確認該表所屬schema,執行如下SQL:
- SELECT n.nspname as "Schema",
- c.relname as "Name"
- FROM pg_catalog.pg_class c
- LEFT JOIN pg_catalog.pg_namespace n
- ON n.oid = c.relnamespace
- WHERE relname = 'insured';
(7)通過gsql連接CN實例,最后再通過table_skewness()函數進行核實確認。