我编写了一个在 sqlite 上运行良好的迁移脚本,但如果我尝试将其应用于 postgres,它就会永远卡住。通过一个简单的 ps,我可以看到 postres 停留在“创建表等待”上。有什么最佳做法吗?
4 回答
如果它真的卡在锁上了,你需要看看它在等待什么。卡在锁上会很奇怪CREATE TABLE
,但这并非不可能。
获取卡住的进程id
获取等待后端的进程ID。您可以在 中找到它ps
,或者通过SELECT
从中找到它pg_stat_activity
,寻找具有waiting
true 的进程,以找到您感兴趣的命令:
SELECT * FROM pg_stat_activity WHERE waiting;
弄清楚它在等待什么锁
通过查询查看卡住的 pid 正在等待的锁pg_locks
:
SELECT * FROM pg_locks WHERE pid = <the-waiting-pid> AND NOT granted;
您可以将这两个步骤与:
\x
SELECT *
FROM pg_locks l
INNER JOIN pg_stat_activity s ON (l.pid = s.pid)
WHERE waiting
AND NOT granted;
然后查看结果,或LIKE
在字段上使用过滤器s.query
来查找您尝试识别锁定问题的查询。
找出谁持有那把锁
您现在可以查询pg_locks
以找出哪个进程找到了该锁,以及它们在做什么。
假设我们发现create
正在等待一个 locktype= relation
lock of mode= AccessExclusiveLock
on relation=14421
被授予。我们希望找到其他会话对该关系持有的锁:
SELECT *
FROM pg_locks l
INNER JOIN pg_stat_activity s ON (l.pid = s.pid)
WHERE locktype = 'relation'
AND relation = 14421;
这应该告诉您是什么阻止了创建。
皱纹
PostgreSQL wiki 上有一个方便的锁监控查询,但它只能找到行级锁。所以一般对DDL没有帮助。
另外,我故意不将所有内容合并到一个查询中。在 AccessExclusiveLock 的情况下,找到通过 pid 阻塞给定后端的锁持有者很简单,但是对于较弱的锁请求,这并不简单——我必须写出哪些锁与哪些锁冲突的规则在 SQL 中,这非常复杂。最好只是目不转睛。
您总是可以重新启动 postgresql。
您的数据库很可能被另一个查询锁定。
特别是如果你用他们的 GUI pgAdmin 做一些事情,我发现这种情况经常发生。(截断表特别棘手,有时 pgAdmin 崩溃并且数据库卡住了)
您要做的是重新启动完整的 postgresql 服务并重试。
确保您:
- 尽量减少 GUI pgadmin 的使用
- 如果不需要它们,请使用 psycopg2 关闭游标/数据库
对于遇到此问题的任何人,以下是为我解决的问题:
alembic 的标准 env.py 包含该段落
with context.begin_transaction():
logger.info("Running Transaction.")
context.run_migrations()
但是,如果您随后在迁移脚本中使用
config = op.get_context().config
engine = engine_from_config(config.get_section(
config.config_ini_section), prefix='sqlalchemy.')
事务将卡在“空闲事务”中。我不太清楚为什么,但它看起来像是事务中的事务,而外部事务从未提交。
要解决此问题,只需删除外部 begin_transaction()
# with context.begin_transaction():
logger.info("Running Transaction.")
context.run_migrations()
你应该很高兴。