【发布时间】:2010-11-06 23:25:27
【问题描述】:
我通过 phpPgAdmin 界面在一个大型 PostgreSQL 表上运行了一条更新语句。由于运行时间过长而超时。
我现在可以更新该表中的一些行,但不是全部。尝试更新某些行会挂起。
行是否被锁定?如何允许更新这些行?
【问题讨论】:
标签: sql database postgresql
我通过 phpPgAdmin 界面在一个大型 PostgreSQL 表上运行了一条更新语句。由于运行时间过长而超时。
我现在可以更新该表中的一些行,但不是全部。尝试更新某些行会挂起。
行是否被锁定?如何允许更新这些行?
【问题讨论】:
标签: sql database postgresql
可以看到锁。
这是一个比直接使用 pg_locks 更容易一点的视图:
CREATE OR REPLACE VIEW public.active_locks AS
SELECT t.schemaname,
t.relname,
l.locktype,
l.page,
l.virtualtransaction,
l.pid,
l.mode,
l.granted
FROM pg_locks l
JOIN pg_stat_all_tables t ON l.relation = t.relid
WHERE t.schemaname <> 'pg_toast'::name AND t.schemaname <> 'pg_catalog'::name
ORDER BY t.schemaname, t.relname;
然后你只需从视图中选择:
SELECT * FROM active_locks;
然后杀死它:
SELECT pg_cancel_backend('%pid%');
【讨论】:
active_locks 的视图或表。你的意思可能是pg_locks?
pg_cancel_backend 与此处的qeury 结合使用:stackoverflow.com/a/10317371/301277 允许我删除所有“被遗忘”的锁。谢谢!
简单:
从 pg_locks 获取活动锁:
SELECT t.relname, l.locktype, page, virtualtransaction, pid, mode, granted
FROM pg_locks l, pg_stat_all_tables t
WHERE l.relation = t.relid
ORDER BY relation asc;
从上面的结果复制pid(例如:14210)并替换为下面的命令。
SELECT pg_terminate_backend(14210)
【讨论】:
pg_cancel_backend(14210) 将取消带有 SIGINT 的查询与 SIGTERM,documentation pg_terminate_backend(14210) 将终止会话以及查询。
您运行的是哪个版本的 PostgreSQL?以下假设是 8.1.8 或更高版本(它可能也适用于早期版本,我不知道)。
我认为您的意思是 phpPgAdmin 超时——PostgreSQL 后端将花费完成查询/更新所需的时间。在这种情况下,原始会话可能仍然存在并且 UPDATE 查询仍在运行。我建议在托管 PostgreSQL 服务器进程的机器上运行以下查询(取自 chapter 24 of the PostgreSQL docs),以查看会话是否仍然存在:
ps auxwww|grep ^postgres
应该出现几行:1 行用于postmaster 主进程,1 行用于“writer”、“stats buffer”和“stats collector”进程。任何剩余的行都用于为数据库连接提供服务的进程。这些行将包含用户名和数据库名称。
希望您可以从中看到您执行原始 UPDATE 的会话是否仍然存在。虽然理论上你可以通过SELECTing 从系统视图pg_stat_activity 中找到更详细的信息,但默认情况下,PostgreSQL 未设置为填充最有用的字段(例如current_query 和query_start)。请参阅第 24 章了解如何在未来启用此功能。
如果您看到会话仍然存在,请将其终止。您需要以运行该进程的用户(通常是 postgres)或 root 身份登录 - 如果您自己不运行服务器,请让您的 DBA 为您执行此操作。
还有一件事:为了更新表中的行,PostgreSQL 避免使用锁。相反,它允许每个写入事务创建一个新的数据库“版本”,当事务提交时,它成为“当前版本”,前提是它不与其他事务同时进行的更新发生冲突。所以我怀疑你看到的“挂起”是由其他原因引起的——虽然我不确定是什么。 (你有没有检查明显的东西,比如包含数据库的磁盘分区是否已满?)
【讨论】:
postgres 15398 ... idle in transaction 或其他什么的地方,然后在Putty 中输入kill 15398。
为了从 Postgres 中释放可能的锁,我通常按顺序执行这些操作。
通过运行以下查询在您的数据库中查找长时间运行的查询。这将帮助您获取阻止更新的长时间运行查询的 PID。
SELECT
pid,
now() - pg_stat_activity.query_start AS duration,
query,
state
FROM pg_stat_activity
WHERE (now() - pg_stat_activity.query_start) > interval '5 minutes';
或者如果您可以通过运行此查询找出哪些进程在特定表上持有锁
SELECT *
FROM pg_locks l
JOIN pg_class t ON l.relation = t.oid AND t.relkind = 'r'
WHERE t.relname = 'Bill';
一旦您确定“活动”的 PID 并阻止您的更新,您就可以通过运行此查询来终止它。终止进程需要一些时间。
SELECT pg_cancel_backend(__pid__);
通过运行查询 2 检查进程是否被终止。如果它仍然处于活动状态,则通过运行此查询来终止此进程。
SELECT pg_terminate_backend(__pid__);
【讨论】:
这将清除所有表上的所有锁。
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE pid <> pg_backend_pid();
【讨论】:
我从未使用过 PostreSql,但如果它与其他类似,我会说你必须终止连接/结束持有锁的事务。
【讨论】: