执行CREATE INDEX后如果长时间没有返回,pg_stat_progress_create_index视图可以实时显示构建进度,避免DBA在等待中盲目猜测。该视图随PostgreSQL 12及以上版本提供,属于动态统计视图,专门报告普通CREATE INDEX与REINDEX命令的执行情况。对于大表上的索引构建,通过它能够看到扫描了多少数据块、处理了多少元组,以及当前处于哪个阶段,从而判断任务是否持续向前推进。这个视图的查询开销极低,可以放心地在生产环境中按需检索。

与常规的pg_stat_activity不同,pg_stat_progress_create_index专注于索引构建的生命周期,信息粒度更细。它不会记录CREATE INDEX CONCURRENTLY,因为并发构建采用多阶段扫描和等待策略,进度模型不适合用简单的块计数表示。理解这一点有助于避免在监控并发索引时误以为视图失效。
视图支持的命令与限制
pg_stat_progress_create_index只追踪普通的CREATE INDEX命令,以及REINDEX INDEX、REINDEX TABLE、REINDEX SCHEMA和REINDEX DATABASE等变体。这些操作在执行期间,每个后端进程都会在该视图中产生一条记录,记录中包括命令类型、目标表、目标索引、当前阶段和各项进度计数。对于分区表上的CREATE INDEX或REINDEX,该视图会显示整体构建进度,其中partitions_total和partitions_done字段可以反映总共需要处理的分区数以及已经完成构建的分区数。
需要注意,CREATE INDEX CONCURRENTLY不会被记录到这个视图中。这是因为并发索引构建需要等待已有事务完成、与读写并发协调,并且可能进行多次表扫描和索引验证,其进度无法简单地用数据块或元组计数来表达。如果你需要监控并发索引的进度,可以退而使用pg_stat_activity查看其等待事件和运行时长,或者结合日志输出辅助判断。
权限方面,普通用户通常只能看到与自己会话对应的进度行,而超级用户或具备pg_read_all_stats角色的用户可以看到所有正在执行的索引构建任务。如果在执行CREATE INDEX期间查询该视图没有返回行,可以先确认索引构建命令是否确实为普通CREATE INDEX或REINDEX,并检查查询是否使用了正确的数据库连接。
关键字段与阶段解读
pg_stat_progress_create_index中最核心的字段是phase,它表示当前索引构建所处的阶段。主要阶段包括initializing(初始化索引元数据)、waiting for lockers(等待持有相关锁的事务结束)、building index(扫描表数据并构建索引)、waiting for writers(等待可能写入表的事务)、validating index(验证索引结构完整性)以及waiting for readers(等待可能读取表的事务)等。如果phase长时间停留在waiting for lockers或waiting for writers,通常意味着有其他事务阻塞了索引构建,需要进一步调查锁情况。
进度计数方面,blocks_total和blocks_done表示构建索引需要扫描的磁盘数据块总数和已经扫描完成的数量,这可以粗略反映底层表扫描的进度。tuples_total和tuples_done则表示需要处理的元组总数和已经处理完成的元组数,这个指标更贴近索引条目构建的实际工作量。对于包含表达式或部分索引的情况,元组处理进度可能比数据块扫描进度更有参考价值。另外,lockers_total、lockers_done和lockers_pid字段专门用于追踪等待其他后端释放锁的过程,帮助定位具体阻塞来源。
command字段用于区分当前任务是CREATE INDEX还是REINDEX。index_relid字段显示正在构建的索引OID,可以通过将其转换为regclass来获得索引名称。relid字段则是目标表的OID。这些字段组合起来,可以精确判断当前数据库中有哪些索引正在构建、构建到哪一步、是否遇到等待。
实际监控查询示例
下面这条SQL可以一次性查看当前所有正在执行的索引构建任务的关键信息:
SELECT pid,
datname,
relid::regclass AS table_name,
index_relid::regclass AS index_name,
command,
phase,
lockers_total,
lockers_done,
blocks_total,
blocks_done,
tuples_total,
tuples_done,
partitions_total,
partitions_done
FROM pg_stat_progress_create_index;
执行后,如果当前有索引构建任务,就会看到一行或多行结果。phase字段显示了任务当前所处的阶段,而blocks_done与blocks_total的对比可以直观地看出底层表扫描已经完成了多少。需要注意的是,这些计数在索引构建过程中会持续增长,因此多次查询可以看到进度变化,从而判断任务是否仍在推进。
为了获得更直观的百分比进度,可以计算blocks_done和blocks_total的比值,并关联pg_stat_activity获取命令开始时间,以便估算已耗时。示例SQL如下:
SELECT p.pid,
p.phase,
CASE WHEN p.blocks_total = 0 THEN NULL
ELSE round(100.0 * p.blocks_done / p.blocks_total, 2)
END AS blocks_pct,
CASE WHEN p.tuples_total = 0 THEN NULL
ELSE round(100.0 * p.tuples_done / p.tuples_total, 2)
END AS tuples_pct,
now() - a.query_start AS elapsed
FROM pg_stat_progress_create_index p
JOIN pg_stat_activity a ON a.pid = p.pid;
在psql中,如果希望持续观察进度变化,可以使用反斜杠命令\watch周期性地重复执行查询。例如,每隔2秒刷新一次进度:
SELECT pid, phase, blocks_done, blocks_total, tuples_done, tuples_total FROM pg_stat_progress_create_index; \watch 2
\watch是psql客户端命令,它会在每次查询后等待指定秒数再重新执行,非常适合在终端中实时盯进度。退出监视只需按下Ctrl+C。
诊断阻塞与常见问题
如果phase长期停留在waiting for lockers、waiting for writers或waiting for readers,通常说明有其他事务正在持有索引构建所需的锁,导致任务无法继续。此时可以关联pg_locks和pg_stat_activity来定位阻塞源。下面这条SQL可以帮助找出正在等待的索引构建任务以及相关的锁信息:
SELECT p.pid,
a.wait_event_type,
a.wait_event,
l.locktype,
l.mode,
l.granted,
a.query
FROM pg_stat_progress_create_index p
JOIN pg_stat_activity a ON a.pid = p.pid
LEFT JOIN pg_locks l ON l.pid = p.pid
WHERE p.phase LIKE 'waiting%';
查询结果中的wait_event_type和wait_event可以揭示当前等待的具体事件,例如Lock或relation相关事件。同时,locktype、mode和granted字段能够帮助判断索引构建究竟在等待哪种类型的锁,以及该锁是否已经被授予。根据这些信息,可以进一步从pg_stat_activity中找到持有冲突锁的后端,并决定是等待其完成还是评估是否需要终止该阻塞事务。
另一个常见问题是误以为CREATE INDEX CONCURRENTLY也会出现在该视图中。如果监控并发索引构建,应该关注pg_stat_activity中的状态和等待事件。对于普通CREATE INDEX,如果发现blocks_done增长非常缓慢,可能意味着底层存储I/O存在瓶颈,或者索引构建过程中的排序溢出到磁盘。此时可以考虑适当调大maintenance_work_mem参数以减少排序溢出,或者调整并行度参数(如max_parallel_maintenance_workers)来加速索引构建。需要注意的是,修改这些参数前应评估服务器可用内存,避免对其他查询造成负面影响。
总体而言,pg_stat_progress_create_index为PostgreSQL索引构建提供了细粒度的进度观察能力。通过理解其字段含义并结合实际查询,DBA可以在索引构建过程中及时发现阻塞与性能瓶颈,从而减少不必要的等待和盲目操作。
PostgreSQLpg_stat_progress_create_index索引创建进度修改时间:2026-08-26 03:42:03