仕組みから学ぶ Web

データ / DB 設計

正しく保ち、速く引く

テーブル設計は「同じ事実を2か所に書かない」ことから始まり、インデックスは「読む行を減らす」ためにある。そしてトランザクションの分離レベルは、同時に動く処理がお互いをどこまで見てよいかの取り決め。遅いクエリの原因は、たいていこの3つのどれか。

読み終わると、これに答えられるようになります

  • ?複合インデックスの列の順番はなぜ重要なのか
  • ?READ COMMITTED で起きて REPEATABLE READ で起きない異常は何か
  • ?件数が増えたら急に遅くなったクエリの、最初に見る場所はどこか
基礎14

正規化 — 同じ事実を2か所に書かない

正規化は理論ではなく「更新時に矛盾が起きない形」を作る作業。どこまで正規化し、どこで意図的に崩すか。

商品名を注文テーブルにも持たせた結果、同じ商品なのに表記が3種類に分裂した

応用16

インデックス — 読む行を減らすための索引

B-tree が何をしているかと、複合インデックスの列順がなぜ効くのか。張れば速くなるものではない。

遅いクエリに片っ端からインデックスを張り、書き込みが3倍遅くなった

発展16

トランザクションと分離レベル — 同時に動く処理が互いをどこまで見てよいか

在庫が二重に引かれる、残高がずれる。同時実行の事故は、分離レベルの選択と設計の両方で決まる。

在庫チェックと在庫更新の間に別の注文が入り、在庫1個の商品が2人に売れた

応用13

N+1 問題 — 1回で済むはずの問い合わせが100回になる

ORM の便利さが隠してしまう問い合わせ回数。発見の仕方と、対処の選択肢を使い分ける。

1件あたり2msのクエリが200回走り、一覧ページの表示に4秒かかっていた

発展15

実行計画 — DB が何をしようとしているかを読む

推測でチューニングしない。EXPLAIN の読み方と、見積もりと実測のズレが何を意味するか。

統計情報が古く、インデックスがあるのにフルスキャンが選ばれ続けていた

応用15

RDB と NoSQL — 問い合わせの形を、いつ決めるか

性能の比較ではなく「アクセスパターンがもう固まっているか、まだ動くか」で選ぶ。後から取り方を増やしたくなったとき、何が起きるかの違い。

取り方が固まる前に NoSQL を選び、後から来た検索要件が全件走査になった

応用15

マイグレーション — 流した瞬間に、書き込みが全部待つ

列を1つ足すだけの変更が、本番で11分サイトを止める。行数ではなく、同時に走っているトランザクションの長さが効く。

列を1つ足すだけの変更で、書き込みが11分間詰まってサイトが止まった