12

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

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

但是,尽管表完全为空,但用于删除表上的第一个外键约束的 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 查询本身。没有其他锁,也没有等待锁的进程。

4

1 回答 1

16

检查 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,请适当地更改查询。或更新。)

于 2013-07-12T01:30:26.793 回答