DBAtlas · 数据库运维图谱

缓存命中率低(buffer/cache hit)

缓存命中率低;数据不断从磁盘(或数据源)读取。确定问题出在数据库 buffer/shared cache 还是 Redis/应用缓存,然后进行测量和修复。

哪个缓存的命中率低?

测量命中率并隔离问题:是数据库 buffer/shared cache 命中率低(物理读高),还是 Redis/应用缓存出现大量未命中和淘汰?

SELECT ROUND((1-(pr.value/(dbg.value+cg.value)))*100,2) AS buffer_hit_pct
FROM v$sysstat pr, v$sysstat dbg, v$sysstat cg
WHERE pr.name='physical reads' AND dbg.name='db block gets' AND cg.name='consistent gets';
  • 数据库 buffer/shared cache 命中率低
  • Redis/应用缓存中大量未命中 / 淘汰

为什么从磁盘读取:容量问题还是扫描模式问题?

buffer 命中率低有两个典型原因:频繁访问的数据(工作集)放不进内存(缓存太小),或者大型全表扫描用一次性数据块污染缓存,将有用的页挤出。

SELECT component, current_size/1024/1024 AS mb FROM v$sga_dynamic_components WHERE component LIKE '%buffer cache%';
SELECT sql_id, disk_reads, executions FROM v$sql ORDER BY disk_reads DESC FETCH FIRST 10 ROWS ONLY;
  • 工作集放不进 RAM(缓存太小)
  • 全表扫描污染缓存

Redis 为什么未命中:maxmemory 淘汰还是 TTL/键管理?

如果 Redis 命中率低,要么是内存达到 maxmemory、键正在被淘汰,要么是键的 TTL 管理/缓存模式较弱(冷键、复用率低)。

INFO memory
# used_memory, maxmemory, maxmemory_policy, evicted_keys
CONFIG GET maxmemory-policy
INFO keyspace
# Key count and expires (keys with TTL) ratio per db
  • maxmemory 已满,淘汰率高
  • TTL/键模式较弱(复用率低)

根本原因:缓存相对于工作集太小

频繁访问的数据大于分配的 buffer/cache,因此不断被淘汰并从磁盘重新读取。命中率低,物理读高。

根本原因:扫描模式污染缓存

大型全表扫描用只使用一次就丢弃的数据块填满缓存,将热页挤出;这会降低命中率。

根本原因:Redis maxmemory 淘汰

Redis 内存已达到 maxmemory 上限;旧键被淘汰以便为新键腾出空间(evicted_keys 持续上升)。这会丢失仍然需要的条目,并降低命中率。

根本原因:TTL / 缓存模式较弱

要么键根本没有设置 TTL,导致内存被冷数据填满,要么缓存模式的复用率低,导致大多数请求最终都未命中。

在 DBAtlas 中打开 →