在PostgreSQL中,分區表是應對資料不斷增長的有效手段,可通過分區裁剪來加速查詢。PolarDB PostgreSQL版列存索引也支援分區表,能夠進一步應對分區表的統計和分析需求。
背景
隨著業務系統的不斷運轉,將產生大量的歷史資料,導致表的規模越來越大,一般會將資料按照時間、user_id 等維度進行分區,每個分區只保留部分的資料。 原生PostgreSQL在查詢時也會通過分區裁剪來避免無關資料的讀取。
PolarDB PostgreSQL版的列存索引也支援對分區表的加速分析,使用方式與現有分區表索引一致。
效果展示
在4並行度模式下,列存索引在三條查詢語句中都比原生PostgreSQL並存執行快35倍以上。
查詢語句 | PostgreSQL原生並行 | 列存索引 |
Q1 | 2.13 s | 0.05 s |
Q2 | 6.42 s | 0.18 s |
Q3 | 10.51 s | 0.30 s |
實施步驟
步驟一:環境準備
請確認您的叢集版本與配置是否滿足以下條件:
叢集版本:
PostgreSQL 16(核心小版本為2.0.16.8.3.0及以上)
PostgreSQL 14(核心小版本為2.0.14.10.20.0及以上)
原表必須包含主鍵,且在建立列存索引時需要將主鍵列加入列存索引中。
wal_level參數的值需設定為logical,即在預寫式日誌WAL(Write-Ahead Logging)中增加支援邏輯編碼所需的資訊。說明您可以通過控制台設定wal_level參數。修改該參數後叢集將會重啟,請在修改參數前做好業務安排,謹慎操作。
開啟列存索引功能。
對於不同的PolarDB PostgreSQL版核心版本,開啟列存索引的方式不同:
步驟二:資料準備
本案例中,會建立一個多級分區表,並類比插入3.2億條資料(約16 GB),之後根據分區條件進行統計分析。
測試用分區表結構如下:
sales:主表。sales_2023:按照年份分區。sales_2023_a:按照月份分區,1~6月定義為分區a。sales_2023_b:按照月份分區,7~12月定義為分區b。
sales_2024:按照年份分區。sales_2024_a:按照月份分區,1~6月定義為分區a。sales_2024_b:按照月份分區,7~12月定義為分區b。
建立名為
sales的多級分區表,以時間列sale_date作為分區鍵,定義如下。CREATE TABLE sales ( sale_id serial, product_id int NOT NULL, sale_date date NOT NULL, amount numeric(10,2) NOT NULL, primary key(sale_id, sale_date) ) PARTITION BY RANGE (sale_date); CREATE TABLE sales_2023 PARTITION OF sales FOR VALUES FROM ('2023-1-1') TO ('2024-1-1') PARTITION BY RANGE (sale_date); CREATE TABLE sales_2023_a PARTITION OF sales_2023 FOR VALUES FROM ('2023-1-1') TO ('2023-7-1'); CREATE TABLE sales_2023_b PARTITION OF sales_2023 FOR VALUES FROM ('2023-7-1') TO ('2024-1-1'); CREATE TABLE sales_2024 PARTITION OF sales FOR VALUES FROM ('2024-1-1') TO ('2025-1-1') PARTITION BY RANGE (sale_date); CREATE TABLE sales_2024_a PARTITION OF sales_2024 FOR VALUES FROM ('2024-1-1') TO ('2024-7-1'); CREATE TABLE sales_2024_b PARTITION OF sales_2024 FOR VALUES FROM ('2024-7-1') TO ('2025-1-1');產生資料並寫入到分區表,約16 GB。
INSERT INTO sales (product_id, sale_date, amount) SELECT (random()*100)::int AS product_id, '2023-01-1'::date + i/3200000*7 AS sale_date, (random()*1000)::numeric(10,2) AS amount FROM generate_series(1, 320000000) i;為表建立列存索引,將
sale_id、product_id、sale_date和amount欄位加入到列存索引。CREATE INDEX ON sales USING CSI(sale_id, product_id, sale_date, amount);
步驟三:執行查詢
使用不同執行引擎進行查詢。根據不同的分區條件產生三條查詢語句Q1,Q2和Q3。
使用列存索引
--- 開啟列存索引,設定查詢並行度為4 SET polar_csi.enable_query to on; SET polar_csi.exec_parallel to 4; --- Q1 EXPLAIN ANALYZE SELECT sale_date, COUNT(*) FROM sales WHERE sale_date BETWEEN '2023-1-1' and '2023-3-1' AND amount > 100 GROUP BY sale_date; --- Q2 EXPLAIN ANALYZE SELECT sale_date, COUNT(*) FROM sales WHERE sale_date BETWEEN '2023-1-1' and '2023-9-1' AND amount > 100 GROUP BY sale_date; --- Q3 EXPLAIN ANALYZE SELECT sale_date, COUNT(*) FROM sales WHERE sale_date BETWEEN '2023-1-1' and '2024-3-1' AND amount > 100 GROUP BY sale_date;關閉列存索引,使用行存引擎
--- 關閉列存索引,使用行存引擎,並設定查詢並行度為4 SET polar_csi.enable_query to off; SET max_parallel_workers_per_gather to 4; --- Q1 EXPLAIN ANALYZE SELECT sale_date, COUNT(*) FROM sales WHERE sale_date BETWEEN '2023-1-1' and '2023-3-1' AND amount > 100 GROUP BY sale_date; --- Q2 EXPLAIN ANALYZE SELECT sale_date, COUNT(*) FROM sales WHERE sale_date BETWEEN '2023-1-1' and '2023-9-1' AND amount > 100 GROUP BY sale_date; --- Q3 EXPLAIN ANALYZE SELECT sale_date, COUNT(*) FROM sales WHERE sale_date BETWEEN '2023-1-1' and '2024-3-1' AND amount > 100 GROUP BY sale_date;





