DBAtlas · データベース運用アトラス

キャッシュヒット率が低い (buffer/cache hit)

キャッシュヒット率が低く、データが常にディスク (またはソース) から読み取られている。問題が DB のバッファ/共有キャッシュにあるのか、Redis/アプリケーションキャッシュにあるのかを判断し、測定して修正する。

どのキャッシュのヒット率が低いか?

ヒット率を測定して問題を切り分ける: データベースのバッファ/共有キャッシュが低い (物理読み取りが多い) のか、それとも 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';
  • DB のバッファ/共有キャッシュのヒット率が低い
  • Redis/アプリケーションキャッシュでミス / エビクションが多い

なぜディスクから読み取っているのか: サイズか、スキャンパターンか?

バッファヒット率が低い典型的な原因は 2 つ: 頻繁にアクセスされるデータ (ワーキングセット) がメモリに収まらない (キャッシュが小さすぎる)、または大規模なフルテーブルスキャンが 1 回しか使わないブロックでキャッシュを汚染し、有用なページを追い出している。

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/キーのパターンが弱い (再利用が少ない)

根本原因: ワーキングセットに対してキャッシュが小さすぎる

頻繁にアクセスされるデータが割り当てられたバッファ/キャッシュより大きいため、常に追い出されてディスクから再読み取りされている。ヒット率が低く、物理読み取りが多い。

根本原因: スキャンパターンがキャッシュを汚染している

大規模なフルテーブルスキャンが、一度使われて破棄されるブロックでキャッシュを埋め、ホットなページを追い出している。これがヒット率を下げる。

根本原因: Redis の maxmemory によるエビクション

Redis のメモリが maxmemory の上限に達し、新しいキーの領域を確保するために古いキーがエビクトされている (evicted_keys が増え続ける)。これにより、まだ必要なエントリが失われ、ヒット率が下がる。

根本原因: 弱い TTL / キャッシュパターン

キーに TTL がまったく設定されずメモリがコールドなデータで埋まっているか、キャッシュパターンの再利用率が低く、ほとんどのリクエストがミスになっている。

DBAtlas で開く →