分析生产Postgres UPDATE-返回查询缓慢

时间:2019-02-27 21:50:23

标签: postgresql database-performance database-sequence

我们正在运行一个Web应用程序,该应用程序平均有1万活跃用户,由6个webnode提供服务,并由Postgres 9.4.6支持。

我们的监视工具确定了以下运行缓慢的查询,该查询通常具有无法接受的响应时间,在过去几天中偶尔会造成中断。

这是一个小表,基本上是一个内部序列实现(旧式应用程序),用于跟踪每个其他表的唯一ID:

CREATE TABLE ids_for_records
(
  tableid integer NOT NULL,
  id bigint NOT NULL,
  CONSTRAINT ids_for_records_pk PRIMARY KEY (tableid)
)
WITH (
  OIDS=FALSE
);

此表仅包含约200条记录。我们的webapp节点使用此查询来获取专门为其使用的一批ID:

UPDATE ids_for_records
SET id = id + <batchsize>
WHERE tableid = <unique-internal-table-id>
RETURNING id;

我需要找出为什么上述查询的性能在过去几天中明显下降的原因:平均约为1秒,但有时也要花费30-60秒。在高负载期间,所有节点都在多个并行连接上执行完全相同的查询。

更新:查询单个(慢速)查询所持有的锁信息(来自pg_lock,pg_class和pg_stat_activity)表明它是来自其他事务的完全相同的查询 ,正在等待。因此,我们有同时进行的事务试图更新(增加ID值)同一行,因此一个具有所有必需锁的活动块会阻塞其他所有行。

否则数据库是健康的,否则我们的运营团队不会发现任何有关存储,内存或连接的问题;另一个表的大小最近达到了64GB,这可能与此有关。

是否有人知道会导致这种性能下降的原因?与以前相同的负载,但是此瓶颈查询比以前慢了约5倍。

1 个答案:

答案 0 :(得分:0)

以下内容包含一些猜测,请在我猜错的地方纠正我。

查询本身将很快,除非发生非常奇怪的事情。等待行锁定的原因很长。

在事务的整个过程中都持有锁,因此可能是与UPDATE语句在同一事务中处理批处理而阻止了并发会话。

解决方案是使用序列。由于您使用一个中央功能以模块化的方式构建了解决方案,因此解决该问题应该不太困难。

挑战在于获取整批序列值。您可以通过使用咨询锁保护setval来安全地进行此操作,该锁可以在交易结束前释放。有关如何执行此操作的示例,请参见my blog post