Postgres:优化并发的同一行更新

时间:2019-04-05 16:36:38

标签: postgresql go sql-update

问题

我正在使用PostgreSQL v10 + golang,我认为这是一个非常常见的SQL问题:

  • 我有一个表'counters',其中有一个current_value和一个max_value整数列。
  • 严格来说,一旦current_value >= max_value,我想删除请求。
  • 我有几个Kubernetes Pod,对于每个API调用,“计数器”表中的同一行(最坏的情况)中的current_value可能增加1(可以想到作为从分布式主机到同一数据库的并发更新。

在我当前和幼稚的实现中,同一行的多个UPDATE自然会相互阻塞(如果重要,隔离级别为“读取已提交”)。 在最坏的情况下,每秒大约有10个以上的请求会更新同一行。这会造成瓶颈并损害性能,这是我买不起的。


可能的解决方案

我想到了一些解决方案,但它们都牺牲了完整性或性能。唯一可以同时保持两者的声音听起来不太干净,因为这看似常见的问题:

只要计数器current_valuemax_value处于相对安全的距离内(增量> 100),就将更新请求发送到某个通道,该通道将每秒被工作人员刷新一次,汇总更新并立即请求。否则(增量<= 100),请在事务的上下文中进行更新(并遇到瓶颈,但在少数情况下)。这样可以加快更新请求的速度,直到达到极限为止,从而有效地解决了瓶颈。


这可能可以解决我的问题。但是,我不禁想到有更好的方法来解决这个问题。

我没有在网上找到很好的解决方案,即使我的启发式方法行得通,但感觉仍然很不干净,而且缺乏完整性。

非常欢迎采用创造性的解决方案!


编辑:

由于@ laurenz-albe的建议,我试图缩短UPDATE(行被锁定到事务的COMMIT)之间的持续时间。将所有UPDATES推送到事务的末尾似乎已经成功了。现在,我每秒可以处理100多个请求并保持完整性!

1 个答案:

答案 0 :(得分:1)

每秒10个并发更新太少了。只需确保交易尽可能短,就不会有问题。

您的最大问题将是VACUUM,因为许多更新对于PostgreSQL来说可能是最糟糕的工作量。确保您创建的表fillfactor大约为70,并且current_value未被编入索引,以便进行HOT更新。