mybook

第7章 — データベースキャッシュ: 最後の砦

DB の中にもキャッシュがある

「Redis を入れる前に、DB 自体のキャッシュ機能を理解しておくべきだ」とケンジ。

PostgreSQL のキャッシュ階層

Loading diagram...

shared_buffers

PostgreSQL のメインキャッシュ。推奨値は総メモリの 25%

-- shared_buffers の設定
ALTER SYSTEM SET shared_buffers = '4GB';  -- 16GB RAM の場合
 
-- キャッシュヒット率の確認
SELECT 
  sum(blks_hit) AS cache_hits,
  sum(blks_read) AS disk_reads,
  round(sum(blks_hit) / 
    (sum(blks_hit) + sum(blks_read))::numeric * 100, 2) 
    AS hit_ratio
FROM pg_stat_database;

INFO

PostgreSQL のキャッシュヒット率は 99% 以上 を目標にする。95% を下回ったら shared_buffers の増加を検討。

work_mem

ソートやハッシュ操作に使うメモリ。クエリごとに割り当てられる。

-- 大きなソートが必要なクエリの前に
SET work_mem = '256MB';
SELECT * FROM products ORDER BY popularity DESC LIMIT 1000;
RESET work_mem;

MySQL のキャッシュ

InnoDB バッファプール

MySQL/InnoDB のメインキャッシュ。推奨値は総メモリの 70-80%

-- バッファプールサイズの設定
SET GLOBAL innodb_buffer_pool_size = 12884901888;  -- 12GB
 
-- ヒット率の確認
SHOW STATUS LIKE 'Innodb_buffer_pool_read%';

AWS RDS のキャッシュ関連設定

FreshMarket は RDS for PostgreSQL を使用。キャッシュ関連のパラメータグループ設定:

パラメータ推奨値説明
shared_buffers総メモリの 25%メインキャッシュ
effective_cache_size総メモリの 75%クエリプランナーのキャッシュ推定
work_mem64-256MBソート・ハッシュ用
random_page_cost1.1SSD 前提

RDS Proxy

RDS Proxy は AWS マネージドの接続プール。Lambda や ECS からの大量接続を効率的に管理する。

Loading diagram...

接続プール

DB 接続の確立は50-100msかかる。接続プールで再利用する。

Loading diagram...
ツール言語特徴
PgBouncerPostgreSQL 専用、軽量
ProxySQLMySQL 専用、クエリルーティング
HikariCPJavaJVM 最速

クエリ最適化 = 最高のキャッシュ

「最速のクエリは、実行されないクエリだ。次に速いのは、インデックスが効いたクエリだ」

N+1 問題

# ❌ N+1: 商品100件 → 101クエリ
products = Product.all
products.each do |p|
  puts p.category.name  # 各商品で1クエリ
end
 
# ✅ Eager Loading: 2クエリ
products = Product.includes(:category).all
products.each do |p|
  puts p.category.name  # キャッシュ済み
end

マテリアライズドビュー

複雑なクエリ結果をテーブルとして保存する。

CREATE MATERIALIZED VIEW popular_products AS
SELECT p.id, p.name, p.price, 
       COUNT(oi.id) as order_count
FROM products p
JOIN order_items oi ON oi.product_id = p.id
GROUP BY p.id
ORDER BY order_count DESC;
 
-- 定期的にリフレッシュ
REFRESH MATERIALIZED VIEW CONCURRENTLY popular_products;

マナミの DB 最適化

施策効果
shared_buffers を 4GB にヒット率 96% → 99.2%
N+1 を Eager Loading にクエリ数 80% 削減
接続プール(PgBouncer)接続時間 50ms → 1ms
マテリアライズドビュー集計クエリ 2秒 → 5ms

次の章では、複数サーバーにまたがる分散キャッシュの課題と解決策を学ぶ。