【问题标题】:Postgres UPDATE much slower when WHERE clause omitted省略 WHERE 子句时,Postgres UPDATE 慢得多
【发布时间】:2020-03-22 02:48:41
【问题描述】:

我正在寻找线索来理解为什么在 WHERE 子句上的过滤器被省略时,UPDATE 查询变得慢得多。

查询的原始版本,在负载下运行 200 万次,平均每次查询 6ms:

UPDATE items

SET name = $1,
      updated_at = now(),
      txid = txid_current(),
      version = version + 1

WHERE filter1 = $2 AND filter2 = $3 AND version = $4
  RETURNING *;

当我取出AND version = $4时,相同负载测试下的延迟更差(236ms):

UPDATE items

SET name = $1,
      updated_at = now(),
      txid = txid_current(),
      version = version + 1

WHERE filter1 = $2 AND filter2 = $3
  RETURNING *;

filter1 + filter2 的元组上有一个唯一索引,所以它应该总是最多匹配一条记录。并且 PG 必须读取整个记录才能生成新的 MVCC 记录(此查询中还有其他字段未更新),因此 似乎 version = version + 1 的成本应该大致相同无论哪种方式。

由于某些与我们应用 API 设计的其他部分有关的原因,我需要从该查询中删除 version 子句。

我应该注意什么以免遭受这种性能损失?


根据@Laurenz Albe 的要求,以下是EXPLAIN 结果:

with version clause:

UPDATE items
  SET name = $1,
      updated_at = now(),
      txid = txid_current(),
      version = version + 1
  WHERE filter1 = $2 AND filter2 = $3 AND version = $4
  RETURNING *;

Update on items  (cost=0.54..8.58 rows=1 width=637) (actual time=0.553..0.559 rows=1 loops=1)
  Buffers: shared hit=57
  ->  Index Scan using filter1_and_filter2 on items  (cost=0.54..8.58 rows=1 width=637) (actual time=0.064..0.070 rows=1 loops=1)
        Index Cond: (((filter2)::text = 'VBHNTZFLRX1575420065'::text) AND ((filter1)::text = 'UpdateNotifLoadTest'::text))
        Filter: (version = 191)
        Buffers: shared hit=6
Planning time: 0.138 ms
Execution time: 0.609 ms

---------

without version clause:

UPDATE items
  SET name = $1,
      updated_at = now(),
      txid = txid_current(),
      version = version + 1
  WHERE filter1 = $2 AND filter2 = $3
  RETURNING *;

Update on items  (cost=0.54..8.57 rows=1 width=637) (actual time=161.899..161.929 rows=1 loops=1)
  Buffers: shared hit=377
  ->  Index Scan using filter1_and_filter2 on items  (cost=0.54..8.57 rows=1 width=637) (actual time=0.102..0.131 rows=1 loops=1)
        Index Cond: (((filter2)::text = 'RXDJPVBHNT1575419999'::text) AND ((filter1)::text = 'UpdateNotifLoadTest'::text))
        Buffers: shared hit=25
Planning time: 0.140 ms
Execution time: 161.977 ms

【问题讨论】:

  • 请为这两个查询提供EXPLAIN (ANALYZE, BUFFERS) 输出。
  • 也许你有一个带有版本的索引?
  • @LaurenzAlbe:我已经用这些结果编辑了原始问题。
  • 在那些中,没有附加条款的版本实际上更快?另一方面,您似乎没有传递真实数据,因为它没有找到要更新的行
  • 啊,好点子。我会看看我是否可以从负载测试中捕获真正的查询,然后重试。

标签: postgresql


【解决方案1】:

很奇怪。今天重新运行了几次,无法重现。

我之前的方法有一个缺陷。还是可以重现的。根据@Bergi 的请求,我已经更新了实时负载测试中的真实数据捕获。

【讨论】:

  • 上周原始问题中报告的延迟数字(6ms vs 236ms)在今天的负载测试中重现。
猜你喜欢
  • 2011-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-20
  • 2014-04-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多