作者:張曉博
2011年畢業于武漢理工大學,曾任職于人大金倉、北大方正信産研究院、百分點等公司,從事資料庫核心開發工作,現在任職于阿裡雲資料庫事業部,雲化資料倉庫服務 AnalyticDB for PostgreSQL 資料庫核心開發技術專家。
1. 概述
AnalyticDB for PostgreSQL(原HybridDB for PostgreSQL,以下簡稱 ADB PG)是阿裡雲上的MPP資料倉庫服務,其核心采用PostgreSQL引擎,基于開源資料庫 Greenplum 改造,并在此基礎上優化分析性能,其中列存儲 metascan 就是提升資料庫查詢性能的一個關鍵特性。
ADB PG支援列存儲格式,具有較高的資料壓縮能力,以及查詢性能,但是當針對有較高過濾率的查詢條件時,依然要做整列資料讀取,或者建 B-Tree 索引,但是索引也有其應用的限制:一是索引無壓縮,資料膨脹較嚴重;二是結果集大的時候,索引代價比 tablescan 高,索引失效等問題。為此 ADB PG 開發了meta scan 功能,具有很好的過濾性能,并且占用的存儲空間也基本可以忽略不計。
ADB PG 的meta scan是對列存表的一種加強,通過收集列存表列的max/min,并配合 block offset機制,可以實作類似于索引的過濾功能。meta資訊裡儲存列的每個block的max、min,offset,max/min用于條件過濾,block offset用于跳過不滿足過濾條件的block,以達到最大程度的減少列存讀取的IO和block解壓的CPU消耗,進而實作查詢性能的提升。TPC-H 1TB 測試整體提升 29%,對于有高過濾率條件的查詢裡,可以提升最高5倍性能,比如 TPC-H的 Q06、Q12、Q14、Q15。
2. 列存 metascan的實作
ADB PG的 meta scan 機制類似于開源格式 ORC 或者 PARQUET的元資訊,通過meta 資訊過濾掉不滿足條件的列存 block,來提升性能。
如上圖所示,ADB PG的每張列存表的資料分為2部分,一部分是表資料,一部分是meta資料,存儲收集的meta資訊。在scan的時候,先讀取meta資料,根據min、max過濾掉不需要讀取的block,通過block offset直接讀取滿足條件的block,然後把tuple傳回給executor,executor計算後,把結果傳回給用戶端。
ADB PG meta存儲格式如下:
meta資訊按行分為兩級meta:row group meta和batch group meta
-
row group meta:
每張表的meta資訊有多個row group meta組成,每個row group meta的max/min反應了連續的1w行的meta資訊。每個row group meta包含10個row batch meta,如上圖所示,row group的meta為:(min, max) = (1, 4000)。
-
row batch meta:
每個row batch meta的min/max反應了連續1000個行的meta資訊。與row group meta不同的是row batch meta還會記錄覆寫的第一行所在的block 的block offset。
metascan 在掃描時,會順序讀取row group meta,如果過濾條件滿足目前row group的min/max,則依次周遊每個row batch meta,如果過濾條件滿足row batch meta的min/max,則會根據block offset,直接定位到檔案中的block,否則掃描下一個row batch meta;如果過濾條件不滿足目前的row group,這讀取下一個row group meta,如此循環,直到所有的資料周遊完全。
為了簡單并且滿足事務特性,meta資訊我們采用heap表的形式儲存,即meta儲存到輔助表中。在建立一個列存表時,同時建立meta表。這樣通過heap表的mvcc以及事務機制,可以自然的實作meta資訊與表資料資訊的一緻性和原子性。
但是該實作方式有一個問題,按這種方式meta必須覆寫所有的資料,即表上的每一行資料更新,必須更新meta,如果使用者使用單條insert這種方式插入資料,則meta資訊會被頻繁更新,這樣既會降低寫入的性能又會降低查詢是scan meta資訊的性能。為解決這個問題,我們把meta 表分成兩個primary meta 表和secordary meta 表。随着insert/update主表,meta資訊會同步更新到secordary meta表中,當每個row group meta覆寫1w個行時,把meta資訊從secordary meta表移動到primary meta表中,查詢的時候隻查詢primary meta表,這樣就不會因為主表資料的頻繁小量insert/update而導緻primary meta膨脹。但是使用這種meta維護方式,scan就需要對primary meta 沒有覆寫的行做特殊處理,是以meta scan執行邏輯如下:
meta資訊的收集是按segfile來劃分的,是以當一個segfile的meta讀取完後,需要把該segfile檔案尾部的tuple順序傳回給executor。對于primary meta表沒有記錄的segfile,scan完primary meta後,同樣的把這些segfile順序掃描一遍。這樣通過meta scan就可以掃描所有的表資料。
目前的metascan支援如下的資料類型和操作符:
-
支援的類型:
Int2/int4/int8
Float4/float8
Time/timetz/timestamp/timestamptz
Varchar/text/bpchar
cash
-
支援的操作符
=、<、<=、>、>=
and 邏輯運算符
sortkey 是AnalyticDB for PostgreSQL的另一個特性,可以讓表按指定的列排序,其用來指定在單分區内資料進行排序。把metascan與sortkey結合使用,可以更有效的提高meta scan執行的性能。如果列的值在資料檔案中分布比較分散,即使過濾性比較好,meta scan的執行性能可能不好,因為列的值分散在太多的block内,導緻隻能跳過極少的block。這種情況就可以在表上建立 sortkey,使得在單分區内資料有序排列,讓表按照過濾字段排序,這樣相同的值都會集中在一起,這些block都是連續的,這樣在執行metascan時,就可以跳過掉大部分block,進而提升掃描的性能。
3. TPC-H測試
TPCH 是一個測試OLAP資料倉庫性能的标準測試集,其主要評價名額是各個查詢的響應時間,即從送出查詢到結果傳回所需時間,我們在ADB PG上針對meta scan特性測試對tpch的加速效果,針對tpch 1TB資料HDD硬碟測試,在其中4個表上建立了sortkey:
table name | sort key |
---|---|
customer | c_mktsegment |
part | p_brand |
lineitem | l_shipdate |
orders | o_orderdate |
tpch 測試結果如下:
query | metascan | tablescan | 性能提升 (%) |
---|---|---|---|
q01 | 19.347 | 11.199 | 0.00% |
q02 | 55.696 | 59.996 | 7.72% |
q03 | 170.492 | 206.383 | 21.05% |
q04 | 108.586 | 129.101 | 18.89% |
q05 | 160.95 | 165.855 | 3.05% |
q06 | 19.564 | 53.544 | 173.69% |
q07 | 646.875 | 629.539 | |
q08 | 153.666 | 156.489 | |
q09 | 724.835 | 725.829 | |
q10 | 217.339 | 248.316 | 14.25% |
q11 | 30.574 | 29.692 | |
q12 | 44.796 | 113.121 | 152.52% |
q13 | 178.811 | 199.52 | 11.58% |
q14 | 12.194 | 72.635 | 495.66% |
q15 | 39.285 | 115.22 | 193.29% |
q16 | 58.443 | 64.909 | 11.06% |
q17 | 1446.869 | 1394.215 | |
q18 | 1118.851 | 1110.468 | |
q19 | 212.091 | 225.613 | 6.38% |
q20 | 331.7 | 365.711 | 10.25% |
q21 | 1027.04 | 1015.196 | |
q22 | 165.681 | 167.305 | |
Total (GEOMEAN) | 163.315 | 211.372 | 29.43% |
從測試結果看,對于Q03、Q04、Q06、Q10、Q12、Q14、Q15有非常顯著的性能提升,最多提升了5倍左右。對于tpch 整體性能,按Geomean算後,有22%的提升。
對于剩餘的查詢無明顯的性能提升。分析這些查詢的特性,meta scan對于tpch中有強過濾條件的查詢,性能提升較明顯,但對于全表scan或者join則沒有效果。
4. 既有執行個體更新 meta scan
對于阿裡雲 AnalyticDB for PostgreSQL 的現有執行個體,如何使用新的meta scan機制? meta scan在實作的時候做了存儲格式的前向相容,現有執行個體通過小版本更新後,如果要使用新的meta scan特性,則需要重新整理列存表的 meta 資訊,可以使用如下的 UDF 來重新整理某張表的meta資訊:
CREATE OR REPLACE FUNCTION UPGRADE_AOCS_TABLE_META(tname TEXT) RETURNS BOOL AS
$$
DECLARE
tcount INT := 0;
BEGIN
-- CHECK TABLE NAME
EXECUTE 'SELECT COUNT(1) FROM PG_AOCSMETA WHERE RELID = ''' || tname || '''::REGCLASS' INTO tcount;
IF tcount IS NOT NULL THEN
IF tcount > 1 THEN
RAISE EXCEPTION 'found more than one table of name %', tname;
ELSEIF tcount = 0 THEN
RAISE EXCEPTION 'not found target table in pg_aocsmeta, table name:%', tname;
END IF;
END IF;
EXECUTE 'ALTER TABLE ' || tname || ' SET WITH(REORGANIZE=TRUE)';
RETURN TRUE;
END;
$$
LANGUAGE PLPGSQL;
select UPGRADE_AOCS_TABLE_META(tname);
AnalyticDB for PostgreSQL 提供了配置參數rds_enable_column_meta_scan用來啟動和關閉metascan,可以使用如下sql啟動或者關閉目前session的metascan:
-- disable metascan
set rds_enable_column_meta_scan = off;
-- enable metascan
set rds_enable_column_meta_scan = on;
-- show metascan is enable?
show rds_enable_column_meta_scan;
如果需要執行個體級别的開啟或者關閉metascan,可以提工單聯系我們的技術支援同學修改。
5. 結論
ADB PG 的列存儲 meta scan主要是通過row group 和batch group的max/min 過濾不滿足的block,通過block offset,直接讀取滿足條件的block,這種方式減少掃描是的IO以及block解壓時的CPU消耗,是以在查詢的filter具有一定的過濾性時,meta scan可以有比較明顯的性能提升。
ADB PG 基于開源資料庫PostgreSQL/Greenplum建構,由阿裡雲資料庫 OLAP 資料庫團隊維護演進,近期會将全部功能增強開源,回饋開源社群。