寬表模式下,一張表擁有數十個列甚至上百個列,但查詢負載中只需要統計/分析部分列,此時可以使用列存索引進行加速。
背景
在很多SaaS業務系統中,一張表有幾十甚至上百個列,在查詢時往往會面臨較大的技術挑戰:
-
查詢時只需要分析其中的幾個列,但在使用行存結構時,會讀取大量無關的列,增加IO負擔。
-
查詢模式不固定,上百個列在查詢時會存在多種過濾條件,構建複合式索引時需要預先匹配所有的查詢情境,一旦改變查詢條件,複合式索引將失效。
列存索引可以很好地應對上述兩個情境。由於列存索引的內部結構以列為單位,所以讀取一個列時並不會影響另一個列,同時列之間也沒有循序關聯性,所以多個查詢條件的順序性也不會影響列存索引的效果。
效果展示
在一億條資料規模和4並行度模式下,採用列存索引方式的查詢效能為PostgreSQL原生並存執行的30倍。
|
查詢語句 |
PostgreSQL原生並行 |
列存索引 |
|
Q1 |
243 s |
7.9 s |
實施步驟
步驟一:環境準備
-
請確認您的叢集版本與配置是否滿足以下條件:
-
叢集版本:
Oracle文法相容 2.0(核心小版本為2.0.14.10.20.0及以上)
-
wal_level參數的值需設定為logical,即在預寫式日誌WAL(Write-Ahead Logging)中增加支援邏輯編碼所需的資訊。說明您可以通過控制台設定wal_level參數。修改該參數後叢集將會重啟,請在修改參數前做好業務安排,謹慎操作。
-
原表必須包含主鍵,並且在建立列存索引時,需要將主鍵列加入列存索引中。建議使用
SERIAL或BIGSERIAL類型的主鍵,這將顯著提高資料同步的效率。 -
一張表只能建立一個列存索引。
-
-
開啟列存索引功能。
對於不同的PolarDB PostgreSQL版(相容Oracle)核心版本,開啟列存索引的方式不同:
步驟二:資料準備
以一張包含24個列的widecolumntable表為例,包含BIGINT、DECIMAL、TEXT、JSONB、TEXT[]等類型,現要對其中的id_1、domain、consumption、start_time和end_time等五個列進行統計分析,統計每個客戶在過去一年多個domain裡消費的金額。
-
建立一張名為
widecolumntable表,表結構定義如下,然後按照您的需求插入測試資料。CREATE TABLE widecolumntable ( id_1 BIGINT NOT NULL PRIMARY KEY, id_2 BIGINT, id_3 BIGINT, id_4 BIGINT, id_5 BIGINT, id_6 BIGINT, version INT, domain TEXT, consumption DECIMAL(18,3), c_level CHARACTER varying(1) NOT NULL, priority BIGINT, operator TEXT, notify_policy TEXT, call_id UUID NOT NULL, provider_id BIGINT NOT NULL, name_1 TEXT NOT NULL, name_2 TEXT NOT NULL, name_3 TEXT, start_time TIMESTAMP WITH TIME ZONE NOT NULL, end_time TIMESTAMP WITH TIME ZONE NOT NULL, comment JSONB NOT NULL, description TEXT[] NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, updated_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL ); -
將
id_1、domain、consumption、start_time和end_time列加入到列存索引中。CREATE INDEX idx_wide_csi ON widecolumntable USING CSI(id_1, domain, consumption, start_time, end_time);
步驟三:執行查詢
使用不同執行引擎統計過去一年客戶在不同domain中消費金額,並按消費額進行排序。
-
使用列存索引。
---開啟列存索引,設定查詢並行度為4 SET polar_csi.enable_query to on; // 高版本 SET polar_csi.max_parallel_workers to 4; // 低版本 SET polar_csi.exec_parallel to 4; ---Q1 EXPLAIN ANALYZE SELECT id_1, domain,SUM(consumption) FROM widecolumntable WHERE start_time > '20230101' and end_time < '20240101' GROUP BY id_1, domain Order By SUM(consumption);說明polar_csi.max_parallel_workers參數在早期核心版本中名為polar_csi.exec_parallel。對於不支援polar_csi.max_parallel_workers的老核心版本,請使用polar_csi.exec_parallel。Oracle文法相容 2.0:
2.0.14.20.42.0及以下版本請使用
polar_csi.exec_parallel。2.0.14.20.43.0及以上版本請使用
polar_csi.max_parallel_workers。
-
關閉列存索引,使用行存引擎。
---關閉列存索引,使用行存引擎,並設定查詢並行度為4 SET polar_csi.enable_query to off; SET max_parallel_workers_per_gather to 4; ---Q1 EXPLAIN ANALYZE SELECT id_1, domain,SUM(consumption) FROM widecolumntable WHERE start_time > '20230101' and end_time < '20240101' GROUP BY id_1, domain Order By SUM(consumption);