导读:本期聚焦于卡拉米创作的《如何用pg_stat_progress_create_index实时监控PostgreSQL索引创建进度》,敬请观看详情。执行CREATE INDEX之后,数据库长时间没有返回,如何判断它是在正常构建还是已经卡死?PostgreSQL内置的pg_stat_progress_create_index系统视图可以回答这个问题。该视图专门追踪普通的CREATE INDEX和REINDEX命令,为每个正在执行索引构建的会话提供一行实时进度数据,包括当前阶段、已扫描的数据块数、已处理的元组数以及分区表已完成的分区数等关键指标。通过查询这些字段,DBA无需盲目猜测索引构建是否还在推进。例如blocks_done与blocks_total的比值能够粗略反映磁盘扫描进度,tuples_done与tuples_total则反映元组处理进度。当phase长期停留在某些等待阶段时,还能结合锁信息定位阻塞源。本文将从视图支持的命令范围、关键字段含义、实际查询示例以及常见阻塞诊断四个方面,详细讲解如何利用pg_stat_progress_create_index实时掌握PostgreSQL索引创建进度。

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

如何用pg_stat_progress_create_index实时监控PostgreSQL索引创建进度

与常规的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

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。