Alembic迁移与PostgreSQL卡住了?
我写了一个迁移脚本,在sqlite上运行得很好,但如果我尝试在postgres上使用同样的脚本,它就会一直卡住。通过简单的命令查看一下,我发现postgres卡在“创建表”的状态上。有没有什么好的做法可以避免这个问题?
5 个回答
在Postgres上运行以下查询,看看这个查询是否卡住了:
SELECT * FROM pg_stat_activity where state = 'active'
你的数据库很可能被其他查询锁住了。
特别是如果你在使用图形界面工具pgAdmin时,这种情况会经常发生。我发现,清空表格特别麻烦,有时候pgAdmin会崩溃,导致数据库卡住。
你需要做的是重启整个PostgreSQL服务,然后再试一次。
确保你:
- 尽量少用图形界面工具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()
这样就可以正常工作了。
你可以随时重启一下postgresql。
如果真的卡在了一个锁上,你需要看看它在等什么。虽然CREATE TABLE
卡在锁上听起来有点奇怪,但也不是不可能。
获取被卡住的进程ID
首先,找出那个在等待的进程ID。你可以通过ps
命令找到它,或者通过从pg_stat_activity
中SELECT
查询,找出那些waiting
为真的进程,这样就能找到你感兴趣的命令:
SELECT * FROM pg_stat_activity WHERE waiting;
找出它在等哪个锁
通过查询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;
然后查看结果,或者在s.query
字段上使用LIKE
过滤器,找到你想要识别的锁定问题的查询。
找出谁持有那个锁
现在你可以查询pg_locks
,找出哪些进程持有那个锁,以及它们在做什么。
假设我们发现create
在等待一个类型为relation
的锁,模式为AccessExclusiveLock
,关系为14421
。我们想找出其他会话在那个关系上持有的锁:
SELECT *
FROM pg_locks l
INNER JOIN pg_stat_activity s ON (l.pid = s.pid)
WHERE locktype = 'relation'
AND relation = 14421;
这样应该能告诉你是什么阻碍了创建操作。
一些细节
在PostgreSQL的维基上有一个很方便的锁监控查询,但它只会找到行级锁。所以对于DDL(数据定义语言)来说,一般没什么帮助。
另外,我故意没有把所有内容合并成一个查询。对于AccessExclusiveLock
来说,找出阻塞某个特定进程的锁持有者其实很简单,但对于弱锁请求来说就没那么简单了——我得把哪些锁互相冲突的规则写成SQL,这样比较复杂。还是直接看比较好。