postgresql更新查询永远占用3m行

postgresql更新查询永远占用3m行,sql,postgresql,sql-update,database-performance,Sql,Postgresql,Sql Update,Database Performance,这是表架构: 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 (i

这是表架构:

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)
)
这是一个需要很长时间的查询:在3m行上按类别设置权重=0更新页面

查看pg_统计_活动,结果如下:

30366   "2 days 18:32:12.141453"    "user"  "UPDATE page_by_category SET weight=0"
如何检查查询是否被卡住?由于没有IO,CPU占用率高。。。在我的centos上,我正在使用top、iotop来查看cpu使用率还是磁盘使用率,但没有超过5%的使用率


PostgreSQL版本:“x86_64-pc-linux-gnu上的PostgreSQL 10.7”

这应该不会花费太多时间。请终止进程并再次执行查询,然后检查是否再次卡住

SELECT pg_cancel_backend(<pid of the process>)
然后找到你想要杀死的进程

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

SELECT pg_terminate_backend(<pid of the process>)
选择pg_terminate_backend()

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

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

SELECT pg_blocking_pids(30366);
找出这些连接有什么问题,以及为什么它们长时间保持锁定

要杀死他们,快跑

SELECT pg_terminate_backend(?????);
其中
???
是通过上述查询找到的阻塞进程ID之一

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

  • 你的存储速度太慢了

  • 您有昂贵的行级触发器

  • 你有很多索引


此查询不应花费2天时间运行。听起来可能存在某种死锁或争用。我如何检查是否存在死锁?@EmrahMehmedov:可能“仅”一个锁而不是死锁(因为如果是死锁,您会收到错误消息)锁问题出现在查询开始之前我猜?我可以看到查询没有被任何锁阻止…该会话的
状态
列显示了什么?首先,在我取消查询或重新启动数据库之前,我试图了解发生了什么事…如果查询没有被卡住,我不想打断它…尽管我不是Postgres的专家更确切地说是SQL Server,但似乎是出现了死锁情况,或者查询被卡住了。它不会有任何进展。仅对3M行进行更新不会花费太多时间。是否有任何方法可以检查查询是否卡住?肯定有。让我们试着找到方法。您是否尝试过从pg_stat_activity中选择*,其中state='active';执行SELECT pgu阻塞pids(30366);结果是:{}那个么你们必须有非常慢的存储,或者昂贵的行级触发器,或者相当多的索引。老实说,表中的触发器正在与另一台postgresql服务器上的另一个db同步…可能也是网络延迟问题?我不确定的是触发器是否为每个更新的行执行?就像更新行一样,触发器会发送将行更新到另一台服务器,然后又更新到另一行…?是的,这肯定是问题所在。对于每一行,您都会导致至少两倍的网络延迟。让触发器执行复杂的操作或与数据库之外的内容交互几乎总是一个非常糟糕的主意。这应该在应用程序端处理。
SELECT pg_terminate_backend(?????);