PostgreSQL18索引新特性之并行创建GIN索引
在真实的生产环境中,当遇到大表时,如果需要创建GIN索引,速度还是比较慢。在PostgreSQL18中新增了一个新特性使用并行来创建一个GIN索引,类似于BTREE和BRIN,当构建受cpu限制时,这可能会导致显著加速创建索引。
并行创建原理
每个工作进程通过常规的并行扫描机制读取数据子集,并构建对应的索引条目。各工作进程使用本地tuplesort对相同键值的条目进行排序和合并。由于不同进程处理的TID列表(针对同一键值)不存在重叠,合并排序只需简单连接这些列表即可。合并后的条目将被写入供主进程使用的共享元组排序器。
主进程在将排序后的条目写入索引前,需要再次执行合并操作。但通过这种分工方式,大部分工作已在工作进程中完成,主进程只需合并数量较少的大条目,从而提高了整体效率。
该并行机制的实现主要借鉴了BTREE索引的代码架构,并进行了简化处理——剔除了与GIN索引无关的功能(如唯一性检查等)
创建测试用例表并插入数据
CREATE TABLE gin_parallel_test (content int[]) ;
insert into gin_parallel_test
select array[random(1,10000),random(1,10000)] from generate_series(1,50000000) S(i);
串行创建GIN索引
查看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;
创建GIN索引
CREATE INDEX idx_gin_test_serial ON gin_parallel_test
USING gin (content);
CREATE INDEX
Time: 42855.201 ms (00:42.855)

并行创建GIN索引
设置并行参数及maintenance_work_mem
SET min_parallel_table_scan_size = 0;
SET max_parallel_maintenance_workers = 4;
SET maintenance_work_mem = '128MB';
创建GIN索引
drop index idx_gin_test_serial;
CREATE INDEX idx_gin_test_serial ON gin_parallel_test
USING gin (content);
CREATE INDEX
Time: 24511.618 ms (00:24.512)

在上面的进程截图中,我们可以看到多了一个创建索引的并行进程,确实在PG18中可以并行创建GIN索引,从耗时上来说,性能提示1倍左右。
总结
在通过上面的实际验证,在串行创建GIN索引,耗时42.855s,并行创建GIN索引,耗时24.512s,性能大幅提升。当设置并行参数后并执行创建GIN索引的命令,在进程列表中,可以看到一个主进程和1个辅助进程。
参考
https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=8492feb98
https://www.postgresql.org/message-id/6ab4003f-a8b8-4d75-a67f-f25ad98582dc%40enterprisedb.com
– / END / –
可以通过下面的方式联系我
如果这篇文章为你带来了灵感或启发,就请帮忙点赞、收藏、转发;如果文章中不严谨或者错漏之处,请及时评论指正。非常感谢!




