【发布时间】: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