SQL Lab

200 行で SQL を覚え、
3,200 万行でデータベースを理解する

第一部はある小さなオンラインショップのデータ(顧客 10 人、注文明細 200 行)で、SQL とデータベースの考え方を手を動かして身につける。 第二部は同じスキーマが 3,200 万行になった世界で、なぜ速いか・なぜ遅いかを実行計画で確かめる。

どのラボも書き換えて実行できる。壊しても npm run seed:basics /npm run seed で作り直せる。

まず 1 回、叩いてみる
見る場所: 結果の表。10 人の顧客

第一部 DB 基礎編

ある小さなオンラインショップの 200 行のデータで、SQL とデータベースの考え方を身につける。

  1. 00 · 15無料
    データベースとは何か
    表計算のシートと同じ見た目の表から出発し、文字列で頼むと表が返る相手としてデータベースを掴む。
  2. 01 · 25無料
    テーブルを読む、作る
    顧客一覧の表を開き、行・列・主キー・型・NULL に名前を付ける。自分でテーブルを作って行を入れる。
  3. 02 · 30無料
    欲しい行だけ取り出す
    「未発送の注文を新しい順に 10 件」。WHERE / ORDER BY / LIMIT と、NULL の三値論理という最初の驚き。
  4. 03 · 25無料
    数える、合計する、束ねる
    「今月の売上は?」「顧客ごとの注文数は?」。集計関数と GROUP BY、そして 0 件の顧客が消える問題。
  5. 04 · 35無料
    テーブルをつなぐ
    注文に顧客の名前を付ける。JOIN で行が増える・消える感覚、LEFT JOIN、中間テーブル、なぜテーブルを分けるのか。
  6. 05 · 25無料
    データを変える
    INSERT / UPDATE / DELETE。WHERE を忘れると全行が変わる。影響行数を先に数える習慣と、制約が守ってくれること。
  7. 06 · 25無料
    クエリの中にクエリを書く
    SELECT の結果は値にも集合にも表にもなる。IN / EXISTS / 派生テーブル / WITH と、NOT IN の罠。
  8. 6+ · 20 · 補足無料
    補足: 行を潰さずに集計する
    ウィンドウ関数。ROW_NUMBER、累積和、前の行との差。飛ばしても第二部に影響しない。
  9. 07 · 30無料
    途中を見せない
    注文を入れて在庫を減らす 2 つの文を、1 つの操作にする。2 セッションで「COMMIT 前は他人に見えない」を体験する。
  10. 08 · 25無料
    索引という実物
    SHOW INDEX で見える「名前と列を持つ物」。EXPLAIN で「全部読んだ」と「索引で引いた」を初めて見分ける。
  11. 09 · 30無料
    アプリから使う
    接続は相手側のスレッド。プレースホルダと SQL インジェクション、ORM が発行する SQL、N+1。第二部への橋。

第二部 パフォーマンス編

同じショップの 1 年後。注文明細が 3,200 万行になり、アラートが鳴っている。障害調査の手順として実行計画を読む。

  1. 00 · 15無料
    1 年後のショップと、この計器盤
    3,200 万行の注文明細。4 つの計器と 4 つのタブ、実行計画という実物、キャッシュの温度。
  2. 01 · 25無料
    フルスキャンとインデックス — 障害 1: マイページが 4 秒かかる
    同じ 64 行を返すのに 4 秒と 0.2ms。ページ・キー・木の順で、インデックスの中身を開ける。
  3. 02 · 25有料
    実行計画を読む
    木は下から上へ。cost / rows / actual time / loops。推定と実測のズレが、調査で最初に見る場所。
  4. 03 · 25有料
    選択性 — 障害 2: インデックスを足したらタイムアウトが増えた
    9 割が同じ値の列に索引を張ると、オプティマイザが間違える。選択性、統計情報、ヒストグラム。
  5. 04 · 30有料
    複合インデックスとカバリング — 障害 3: 購入履歴の月次集計が遅い
    「この顧客の直近 30 日」を最速で返す設計。複合インデックスの列順と、本体行を読まないカバリング。
  6. 05 · 25有料
    InnoDB の中身
    テーブル本体は主キーの B-tree。同じ行数でも連続とランダムで 25 倍違う理由、バッファプール、UUID 主キー。
  7. 06 · 25有料
    ソートとページング — 障害 4: 注文一覧の 1,000 ページ目が開かない
    Sort が消える条件、ソートのディスク溢れ、OFFSET の線形コストとキーセットページング。
  8. 07 · 25有料
    JOIN — 障害 5: 商品別の売上画面が終わらない
    Nested loop と Hash join。loops の意味、結合列の両側の索引、同じ索引・同じ答えで順番だけ違うと 1,000 倍。
  9. 08 · 25有料
    書き込みの代償と、稼働中の変更
    インデックスは書き込みで払う。INSTANT / INPLACE / LOCK=NONE で止めずに変える。
  10. 09 · 35有料
    ロック — 障害 6: セール開始直後に注文が失敗する
    在庫行のロック待ち、逆順ロックのデッドロック、ギャップロック、インデックスのない UPDATE が全行を止める。
  11. 10 · 30有料
    同時に来る
    同時接続と p99、集計バッチが API を遅くする理由、ホットロウ、スロークエリログ、本番でしか学べない残り。