【问题标题】:postgresql UPDATE query taking forever with 3m rowspostgresql UPDATE 查询永远占用 3m 行
【发布时间】:2021-05-24 15:51:39
【问题描述】:

这是表架构:

CREATE TABLE public.page_by_category
(
    id integer NOT NULL DEFAULT nextval('page_by_category_id_seq'::regclass),
    page_id bigint NOT NULL,
    category_id bigint NOT NULL,
    weight integer NOT NULL,
    CONSTRAINT id_pk PRIMARY KEY (id),
    CONSTRAINT category_id_fkey FOREIGN KEY (category_id)
    CONSTRAINT page_id_fkey FOREIGN KEY (page_id)
)

这是需要很长时间的查询:UPDATE page_by_category SET weight=0 3m 行。

查看 pg_stat_activity 这是结果:

30366   "2 days 18:32:12.141453"    "user"  "UPDATE page_by_category SET weight=0"

如何检查查询是否卡住?由于没有 IO,CPU 使用率很高...在我的 centos 上我使用的是 top,iotop 来查看是否使用了 cpu 或磁盘但仅占 5% 的使用率...

PostgreSQL 版本:""PostgreSQL 10.7 on x86_64-pc-linux-gnu"

【问题讨论】:

  • 此查询不应需要 2 天才能运行。听起来可能存在某种僵局或争用。
  • 如何检查是否有死锁?
  • @EmrahMehmedov:它可能“只是”一个 而不是死锁(因为如果它是死锁,你会收到一条错误消息)
  • 锁定问题出现在查询开始之前我猜?我可以看到查询没有被任何锁阻止...
  • 该会话的state 列显示了什么?

标签: sql postgresql sql-update database-performance


【解决方案1】:

由于您的挂起更新的进程 ID 是 30366,因此您应该查找持有阻塞语句的锁的打开事务:

SELECT pg_blocking_pids(30366);

找出这些连接出了什么问题,以及为什么它们会保持这么长时间的锁定。

要杀死它们,请运行

SELECT pg_terminate_backend(?????);

其中????? 是通过上述查询找到的阻塞进程 ID 之一。

如果阻塞查询的不是锁,则仍然存在以下可能性:

  • 你的存储速度非常慢

  • 你有昂贵的行级触发器

  • 你有很多索引

【讨论】:

  • 执行 SELECT pg_blocking_pids(30366);结果是:{}
  • 那你肯定有非常慢的存储,或者昂贵的行级触发器,或者相当多的索引。
  • 说实话,表有触发器,它正在与另一个 postgresql 服务器上的另一个数据库同步......也可能是网络延迟问题?我不确定是否为每个更新的行执行触发器?像更新行然后触发器将更新的行发送到另一台服务器并再次发送另一行...?
  • 是的,这绝对是问题所在。对于每一行,您至少会产生两倍的网络延迟。拥有一个执行复杂操作或与数据库外部的某些事物交互的触发器几乎总是一个非常糟糕的主意。这应该在应用程序端处理。
【解决方案2】:

这应该不会花费太多时间。杀死进程并再次执行查询,检查是否再次卡住。

SELECT pg_cancel_backend(<pid of the process>)

如果你不知道 pid 那么你可以试试下面的查询:

SELECT * FROM pg_stat_activity WHERE state = 'active';

然后找到你要杀死的进程。

如果进程仍然存在,请尝试:

SELECT pg_terminate_backend(<pid of the process>)

(如果可能,在终止查询后重新启动 DB,然后重试。)

【讨论】:

  • 好吧,首先我想了解发生了什么,然后再取消查询或重新启动数据库……如果查询没有卡住,我不想打断它……
  • 虽然我不是 Postgres 而不是 SQL Server 的专家,但似乎要么存在死锁情况,要么查询只是卡住了它不会去任何地方。只更新 3M 行应该不会花费太多时间。
  • 没有办法检查查询是否卡住了吗?
  • 肯定有。让我们试着找到路。
  • 你试过 SELECT * FROM pg_stat_activity WHERE state = 'active';
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-11
  • 1970-01-01
  • 2017-11-17
  • 1970-01-01
相关资源
最近更新 更多