通过 PK 获取特定单行 id 的查询时间非常慢

mir*_*e2k 8 postgresql performance query-performance

EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS)  
SELECT * 
FROM contract  
WHERE contract.id = 33129;
Run Code Online (Sandbox Code Playgroud)
EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS)  
SELECT * 
FROM contract  
WHERE contract.id = 33129;
Run Code Online (Sandbox Code Playgroud)
EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS)  
SELECT * 
FROM contract  
WHERE contract.id = 33128;
Run Code Online (Sandbox Code Playgroud)
Index Scan using contract_pkey on public.contract  (cost=0.29..8.31 rows=1 width=305) (actual time=0.121..30.386 rows=1 loops=1)
  Output: id, network, address, platform_id, sync_marker, props, sync_marker_alt, interface, ingested_at, data
  Index Cond: (contract.id = 33129)
  Buffers: shared hit=325
Planning Time: 0.098 ms
Execution Time: 30.412 ms
Run Code Online (Sandbox Code Playgroud)

请注意查询时间的巨大差异。分析输出中的唯一提示似乎是共享命中。

这是完全可重复的并且每次都会发生。该表仅包含约 60,000 行。这个生产数据库上还发生了其他事情,所以我认为这个特定行存在一些锁争用?但我不确定如何验证这一点。

编辑:仅查询单个字段会出现相同的问题(尽管现在输出也给了我“堆获取”):

Index Only Scan using contract_pkey on public.contract  (cost=0.29..8.31 rows=1 width=4) (actual time=0.122..45.477 rows=1 loops=1)
  Output: id
  Index Cond: (contract.id = 33129)
  Heap Fetches: 333
  Buffers: shared hit=326
Planning Time: 0.101 ms
Execution Time: 45.499 ms
Run Code Online (Sandbox Code Playgroud)
Index Only Scan using contract_pkey on public.contract  (cost=0.29..8.31 rows=1 width=4) (actual time=0.025..0.026 rows=1 loops=1)
  Output: id
  Index Cond: (contract.id = 33128)
  Heap Fetches: 1
  Buffers: shared hit=4
Planning Time: 0.103 ms
Execution Time: 0.047 ms
Run Code Online (Sandbox Code Playgroud)

VACUUM contract;

不会改变任何东西。

Lau*_*lbe 13

Buffers: shared hit=325
Run Code Online (Sandbox Code Playgroud)

这意味着您必须处理 325 个 8kB 页面才能找到匹配的行。

最可能的解释是 的行上有很多更新id = 33129,并且 autovacuum 尚未清理它们,因此存在大量的索引条目id = 33129,并且索引扫描必须访问表中的所有这些行版本以确定它是否可以看到它们。

问题应该会在一段时间后消失

VACUUM contract;
Run Code Online (Sandbox Code Playgroud)

这应该删除死行版本。

如果没有,则说明您有一个长时间运行的事务、一个陈旧的复制槽或一个准备好的事务阻塞VACUUM进度,您应该修复该问题。

如果VACUUM有帮助,也许您应该减少autovacuum_vacuum_scale_factor该表,以便它更频繁地接收 autovacuum 运行。

VACUUM为了减少面对许多问题的需要UPDATE,尝试获取HOT更新