我们正在运行一个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倍。
答案 0 :(得分:0)
以下内容包含一些猜测,请在我猜错的地方纠正我。
查询本身将很快,除非发生非常奇怪的事情。等待行锁定的原因很长。
在事务的整个过程中都持有锁,因此可能是与UPDATE
语句在同一事务中处理批处理而阻止了并发会话。
解决方案是使用序列。由于您使用一个中央功能以模块化的方式构建了解决方案,因此解决该问题应该不太困难。
挑战在于获取整批序列值。您可以通过使用咨询锁保护setval
来安全地进行此操作,该锁可以在交易结束前释放。有关如何执行此操作的示例,请参见my blog post。