PostgreSQL17索引優化之支持并行創建BRIN索引
最近連續寫了幾篇關于PostgreSQL17優化器改進的文章,其實感覺還是挺有壓力的。對于原理性的知識點,一方面是對這些新功能也不熟悉,為了盡可能對于知識點表述或總結做到準確,因此需要去閱讀官網的討論郵件及源碼;另外對于知識點,如何快速的把自己寫文章的本意,很清晰的表達清楚,也在不斷調整寫作方式。希望不會對大家的閱讀造成困擾,也希望大家有所收獲。
關于PostgreSQL17索引優化之支持并行創建BRIN索引這個主題,相對來說更傾向于實操類型的,對于底層具體是如何實現的,其實對于大部分人來說應該是不太關注。下面我們直接進入正題,直接實操驗證該功能。
創建測試用例表并插入數據
CREATE TABLE brin_parallel_test (a int, b text, c bigint) WITH (fillfactor=40);
--生成的數據中需要有null或非null的值
INSERT INTO brin_parallel_test
SELECT (CASE WHEN (mod(i,231) = 0) THEN NULL ELSE i END),(CASE WHEN (mod(i,233) = 0) THEN NULL ELSE md5(i::text) END),(CASE WHEN (mod(i,233) = 0) THEN NULL ELSE (i/100) + mod(i,8) END)FROM generate_series(1,50000000) S(i);
串行創建BRIN索引
查看max_parallel_maintenance_workers默認參數值
查看max_parallel_maintenance_workers,該參數設置單一工具性命令能夠啟動的并行工作者的最大數目。默認值2,表示條件允許,可以啟動兩個工作程序來幫助創建索引。
testdb=# show max_parallel_maintenance_workers;max_parallel_maintenance_workers
----------------------------------2
(1 row)
設置max_parallel_maintenance_workers值
為了確保不會選擇多核創建索引,在這里將max_parallel_maintenance_workers設置為0
SET max_parallel_maintenance_workers = 0;
創建BRIN索引
CREATE INDEX brin_test_serial_idx ON brin_parallel_testUSING brin (a int4_minmax_ops, a int4_bloom_ops, b, c int8_minmax_multi_ops)WITH (pages_per_range=7);
CREATE INDEX
Time: 52435.488 ms (00:52.435)
并行創建BRIN索引
設置并行參數及maintenance_work_mem
SET min_parallel_table_scan_size = 0;
SET max_parallel_maintenance_workers = 4;
SET maintenance_work_mem = '128MB';
創建BRIN索引
CREATE INDEX brin_test_parallel_idx ON brin_parallel_testUSING brin (a int4_minmax_ops, a int4_bloom_ops, b, c int8_minmax_multi_ops)WITH (pages_per_range=7);
CREATE INDEX
Time: 12246.050 ms (00:12.246)
對比串行和并行串行索引是否一致
SELECT relname, relpagesFROM pg_classWHERE relname IN ('brin_test_serial_idx', 'brin_test_parallel_idx')ORDER BY relname;relname | relpages
------------------------+----------brin_test_parallel_idx | 3brin_test_serial_idx | 3
(2 rows)
--檢查(A except B)和(B except A)是否為空,如果為空,這意味著索引是相同的。
SELECT * FROM brin_page_items(get_raw_page('brin_test_parallel_idx', 2), 'brin_test_parallel_idx')
EXCEPT
SELECT * FROM brin_page_items(get_raw_page('brin_test_serial_idx', 2), 'brin_test_serial_idx');SELECT * FROM brin_page_items(get_raw_page('brin_test_serial_idx', 2), 'brin_test_serial_idx')
EXCEPT
SELECT * FROM brin_page_items(get_raw_page('brin_test_parallel_idx', 2), 'brin_test_parallel_idx');
從這里我們可以看出,對于串行和并行創建的索引,其結果是一致的。
總結
從上述的驗證,在串行創建BRIN索引,耗時52.435s,并行創建BRIN索引,耗時12.246s,性能大幅提升。對于并行創建BRIN索引,當max_parallel_maintenance_workers為4時,通過觀察后臺的進程,是由一個主進程和3個輔助進程來創建索引的。