postgresql – 为什么空表上的ALTER TABLE DROP CONSTRAINT需要很长时间?

我试图在一个事务中将数百万行数据加载到一个表(一个“跟随”表,其中包含两个用户表的外键,以及这些键上的相关索引).我的初始尝试导致我的脚本崩溃,因为系统内存已耗尽.

一些研究得出结论,崩溃是由于外键约束,所以我验证表是空的(即导致进程被杀死的事务没有完成)并修改我的脚本以删除外来键约束和索引以插入数据.我的目的是在之后重新创建约束和索引.

但是,ALTER TABLE DROP CONSTRAINT命令删除表上的第一个外键约束需要很长时间(几十分钟),尽管表完全为空.

我唯一能想到的是它与我写入表中的大量数据有关,然后没有提交,因为脚本崩溃了.但是,当然,由于事务没有提交,我在数据库中找不到任何数据跟踪.

什么可能导致此查询缓慢(或可能根本不运行;在撰写本文时它仍在进行中),我该如何避免它?

数据库中打开了其他事务(迁移其他非常大的表的数小时长事务),但这些事务都没有触及后续表.

编辑:pg锁定如下:

db=# select relation::regclass,* from pg_locks where not granted;
-[ RECORD 1 ]------+--------------------
relation      | auth_user
locktype      | relation
database      | 53664
relation      | 54195
page        |
tuple       |
virtualxid     |
transactionid   |
classid      |
objid       |
objsubid      |
virtualtransaction | 5/343
pid        | 17300
mode        | AccessExclusiveLock
granted      | f

上面的pid(17300)就是ALTER TABLE查询本身.没有其他锁,也没有进程等待锁.

检查pg_locks并验证没有其他事务在表上有锁.即使是读锁定也会阻止ALTER TABLE.
\x

select 
  pg_class.relname,pg_locks.*
from pg_locks 
left outer join pg_class ON (pg_locks.relation = pg_class.oid)
where pg_locks.relation = 'auth_user'::regclass;

通过过滤原始查询中未授予的位置,您只显示未完成的锁,而不是阻止它们的锁.

这个锁没有被授予的事实告诉我这是一个锁定问题.另一个事务持有此表的锁定,阻止ALTER TABLE获取它需要继续的AccessExclusiveLock.这可能只是某个时候从表中选择的事务.

您可以通过加入pg_stat_activity找到它:

select 
  c.relname,l.*,psa.*
from pg_locks l
inner join pg_stat_activity psa ON (psa.pid = l.pid)
left outer join pg_class c ON (l.relation = c.oid)
where l.relation = 'test'::regclass;

这将显示持有或等待此表中的锁的事务,锁是什么,这些事务当前正在运行什么语句等.

(对于旧版本的用户:pg_stat_activity.pid曾经是procpid.所以如果你使用的是旧的Postgresql,请适当更改查询.或者更新.)

相关文章

项目需要,有个数据需要导入,拿到手一开始以为是mysql,结果...
本文小编为大家详细介绍“怎么查看PostgreSQL数据库中所有表...
错误现象问题原因这是在远程连接时pg_hba.conf文件没有配置正...
因本地资源有限,在公共测试环境搭建了PGsql环境,从数据库本...
wamp 环境 这个提示就是说你的版本低于10了。 先打印ph...
psycopg2.OperationalError: SSL SYSCALL error: EOF detect...