PostgreSQL在healthcare schema创建表长期未完成,请求排查原因
以下是针对该问题的具体排查方向:
检查schema相关的锁与阻塞
长时间卡住大概率是锁阻塞导致,执行以下查询查看是否有会话持有healthcare schema相关的锁,或当前CREATE TABLE语句被其他会话阻塞:-- 查看与healthcare schema相关的锁 SELECT * FROM pg_locks WHERE relation = 'healthcare'::regnamespace; -- 查看所有阻塞的会话详情 SELECT blocked_locks.pid AS blocked_pid, blocked_activity.usename AS blocked_user, blocking_locks.pid AS blocking_pid, blocking_activity.usename AS blocking_user, blocked_activity.query AS blocked_query, blocking_activity.query AS blocking_query FROM pg_catalog.pg_locks blocked_locks JOIN pg_catalog.pg_stat_activity blocked_activity ON blocked_locks.pid = blocked_activity.pid JOIN pg_catalog.pg_locks blocking_locks ON blocked_locks.locktype = blocking_locks.locktype AND blocked_locks.database IS NOT DISTINCT FROM blocking_locks.database AND blocked_locks.relation IS NOT DISTINCT FROM blocking_locks.relation AND blocked_locks.pid != blocking_locks.pid WHERE NOT blocked_locks.granted;如果发现阻塞进程,可根据pid终止对应的会话(需谨慎操作):
SELECT pg_terminate_backend(阻塞的pid);检查schema的默认表空间状态
若healthcare schema绑定了异常的表空间(如磁盘满、IO性能极低、挂载异常),会导致表创建卡住。先查询schema的默认表空间:SELECT nspname, spcname FROM pg_namespace JOIN pg_tablespace ON pg_namespace.reltablespace = pg_tablespace.oid WHERE nspname = 'healthcare';对比public schema的表空间(通常是
pg_default),尝试指定正常表空间创建表:CREATE TABLE healthcare.admission_source( admission_source_id INTEGER, admission_source INTEGER, description varchar(255) ) TABLESPACE pg_default;若能快速创建,则说明原表空间存在问题。
排查事件触发器干扰
检查是否存在针对DDL操作(如CREATE TABLE)的事件触发器,且触发器关联的函数存在耗时操作或死循环:SELECT * FROM pg_event_trigger;若存在可疑触发器,可临时禁用后再尝试创建表:
ALTER EVENT TRIGGER 触发器名 DISABLE;(操作后记得恢复)查看当前会话的等待事件
通过pg_stat_activity查看CREATE TABLE语句的等待状态,定位卡住的原因:SELECT pid, query, wait_event_type, wait_event FROM pg_stat_activity WHERE query LIKE '%CREATE TABLE healthcare.admission_source%';根据等待事件判断:比如
wait_event_type为IO则可能是磁盘问题,为Lock则是锁阻塞,为LWLock可能是系统资源竞争。验证schema的系统表状态
若schema相关的系统表存在损坏,也可能导致操作异常。先尝试重新索引schema:REINDEX SCHEMA healthcare;若reindex也卡住,需进一步检查数据库的完整性,可运行
pg_checksums(需开启校验且数据库离线)。排除会话级异常
关闭当前执行CREATE TABLE的会话,开启全新的会话(如新开psql窗口)再次尝试执行语句,避免当前会话未提交事务导致的隐性锁问题。
内容的提问来源于stack exchange,提问作者Langutang

