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

时间:2013-07-11 23:58:53

标签: postgresql postgresql-9.1

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

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

但是,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查询本身。没有其他锁,也没有进程等待锁。

1 个答案:

答案 0 :(得分:11)

检查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;

通过在原始查询中过滤where not granted,您只会显示未完成的锁定,而不会显示阻止它们的锁定。

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

您可以加入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,请相应地更改查询。或者更新。)