Day21 前半のゴール
「“テーブルを分けて速くする”という発想を、自分の言葉で説明できるようになる」
今日のテーマは「パーティショニング」です。
一言でいうと、
巨大テーブルを“論理的には1つのテーブルのまま”、物理的には“分割して持つ”仕組み
です。
前半のゴールはこうです。
なぜ大規模データでパーティショニングが必要になるのかをイメージできる
「テーブルを分割する」と「テーブルを増やす」は何が違うかを説明できる
代表的なパーティションの考え方(特に日付で分割)を理解する
ここまで押さえれば、後半で「MySQL の具体的なパーティション定義」と「注意点」に入っていくとき、迷子になりません。
そもそも、なぜパーティショニングが必要になるのか
「“1テーブルに何億行”になると、インデックスだけではしんどくなる」
まず、前提から整理します。
普通の業務システムなら、テーブルの行数は数万〜数百万行くらいで収まることが多いです。
このくらいなら、インデックス設計とクエリチューニングで十分戦えます。
でも、ログ・アクセス履歴・センサー情報・イベント記録などを扱うと、
平気で「1テーブルに数千万〜数億行」という世界に突入します。
このレベルになると、
インデックスがあっても、ディスクI/Oが重くなる
バックアップ・リストア・ALTER TABLE がとんでもなく遅くなる
古いデータの削除(DELETE)が地獄になる
といった問題が出てきます。
ここで登場するのが「パーティショニング」です。
パーティショニングとは何か
「1つのテーブルを“中で何個かに分割して”持つ仕組み」
パーティショニングを、まずはざっくりイメージで捉えましょう。
アプリやSQLから見ると、テーブルは1つに見える
でも、MySQL の内部では、そのテーブルが複数の“かたまり”に分かれて保存されている
この“かたまり”1つ1つを「パーティション」と呼びます。
例えば、logs というテーブルがあるとして、
2024年のデータ
2025年のデータ
2026年のデータ
を、それぞれ別のパーティションに分けて保存する、というイメージです。
SQL はこう書きます。
SELECT *
FROM logs
WHERE created_at BETWEEN '2025-01-01' AND '2025-01-31';
Python書き方は普通のテーブルと変わりません。
でも、MySQL の内部では、
「2025年のパーティションだけ見ればいいな」
と判断して、他の年のパーティションを無視してくれます。
これがパーティショニングの一番大事なポイントです。
パーティショニングと「テーブルを年ごとに分ける」の違い
「アプリからは“1テーブル”に見えるかどうか」
よくある素朴な対策として、
logs_2024
logs_2025
logs_2026
のように、年ごとにテーブルを分ける、というやり方があります。
これはこれで有効ですが、デメリットもあります。
アプリ側で「どのテーブルを見に行くか」を意識しないといけない
「2024〜2026年のデータをまとめて集計したい」ときに UNION が必要になる
一方、パーティショニングは、
テーブル名は logs のまま
SQL も logs を1つのテーブルとして書ける
内部的にだけ「年ごとのパーティション」に分かれている
という形になります。
つまり、
テーブルを分ける
→ アプリがテーブルの分割を意識する必要がある
パーティショニング
→ アプリは1テーブルとして扱える。分割はDB側の責任
という違いがあります。
アプリのコードをシンプルに保ったまま、大規模データを扱いたいときに、
パーティショニングは強力な選択肢になります。
パーティショニングの一番よくある使い方
「日付で分割して“古いデータを切り捨てやすくする”」
実務で一番よく使われるパーティショニングは、「日付で分割」です。
例えば、アクセスログテーブルを考えます。
CREATE TABLE access_logs (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id INT,
path VARCHAR(255),
created_at DATETIME NOT NULL
) ENGINE=InnoDB;
Pythonこのテーブルが、毎日何十万行も増えていくとします。
1年で数千万行、数年で億単位になります。
ここで、created_at を使って「月ごと」にパーティショニングするイメージです。
2025-01 のデータ → パーティション p202501
2025-02 のデータ → パーティション p202502
…
こうしておくと、メリットがいくつか出てきます。
範囲検索が速くなる
「“関係ない月のパーティション”をそもそも見ない」
例えば、2025年1月のログだけを見たいとき、
SELECT *
FROM access_logs
WHERE created_at BETWEEN '2025-01-01' AND '2025-01-31';
Pythonというクエリに対して、MySQL は、
「2025-01 のパーティションだけ見ればいい」
と判断できます。
結果として、
全パーティションをなめるのではなく、
対象のパーティションだけをスキャンすればよくなる
ので、I/O が減り、クエリが速くなります。
これを「パーティション・プルーニング」と呼びます。
Day21 では名前は覚えなくていいですが、「関係ないパーティションを切り捨てる」というイメージは持っておいてください。
古いデータの削除が一瞬で終わる
「DELETE ではなく“パーティションごと捨てる”」
もう1つの大きなメリットが、「古いデータの削除」です。
パーティショニングしていない巨大テーブルから、
「1年以上前のログを消したい」
となると、普通はこう書きます。
DELETE
FROM access_logs
WHERE created_at < '2024-01-01';
Pythonこれは、対象行を1行ずつ削除していくので、
何百万・何千万行もあると、ものすごく時間がかかります。
ロックも重くなり、他の処理に影響が出ます。
一方、月ごとにパーティショニングしていれば、
「2023年分のパーティションを丸ごと DROP する」
という操作で、一瞬で消せます。
イメージとしては、
巨大なテーブルから古い行を1本ずつ抜くのではなく
「古い引き出しごと捨てる」
感じです。
ログや履歴のように「古いデータは一定期間で捨てる」前提のテーブルでは、
このメリットが非常に大きいです。
パーティショニングの“向き・不向き”
「何でもかんでも分割すればいいわけではない」
ここまで聞くと、「じゃあ全部パーティショニングすればいいじゃん」と思うかもしれませんが、
もちろんそんなに単純ではありません。
パーティショニングが向いているのは、ざっくり言うとこういうテーブルです。
行数がとにかく多い(数千万〜億単位)
特定のカラム(多くは日付)で範囲検索することが多い
古いデータをまとめて削除する運用がある
逆に、向いていないのは、
行数がそこまで多くない(数十万〜数百万程度)
範囲検索よりも「IDで1件だけ取る」ことが多い
古いデータを捨てず、ずっと持ち続ける
といったテーブルです。
パーティショニングには、それなりの複雑さと制約もあるので、
「とりあえず全部パーティションにする」は悪手です。
Day21 前半では、
パーティショニングは“大規模データ専用の武器”であり、
普通のテーブルには不要なことが多い
という感覚だけ持っておいてください。
インデックスとの関係をざっくり押さえる
「パーティションを分けても、インデックス設計は依然として重要」
パーティショニングをすると、
「パーティションさえ分ければ速くなるんでしょ?」
と誤解されがちですが、そうではありません。
パーティショニングは、
「見るべきデータの“かたまり”を減らす」
ための仕組みです。
その“かたまり”の中で、どの行をどう探すか、は
相変わらずインデックスの仕事です。
つまり、
パーティショニング
→ どのパーティションを見るかを減らす
インデックス
→ パーティションの中で、どの行を読むかを減らす
という役割分担になります。
なので、
created_at でパーティショニングしているからといって
user_id のインデックスが不要になるわけではない
ということです。
Day21 後半では、
「パーティションキーの選び方」と「インデックスとの組み合わせ方」を、
もう少し具体的に見ていきます。
Day21 前半のまとめ
パーティショニングは「巨大なテーブルを、アプリからは1テーブルのまま見せつつ、内部的には複数の“かたまり(パーティション)”に分割して保存する仕組み」であり、特にログやアクセス履歴のように行数が爆発しやすいテーブルで、日付(created_at など)を基準に月ごと・年ごとに分割することで「関係ない期間のパーティションをそもそも読まない(範囲検索が速くなる)」「古いデータを DELETE ではなくパーティションごと DROP して一瞬で捨てられる」という大きなメリットを持つ。
一方で、パーティショニングは「何でもかんでもやればいい魔法」ではなく、行数がそこまで多くないテーブルや、主にIDで1件だけ取得するようなテーブルにはあまり向かず、あくまで「数千万〜億行クラス」「日付などで範囲検索が多い」「古いデータをまとめて削除する運用がある」といった“大規模データ専用の武器”として考えるべきであり、パーティションで“見るべきかたまり”を減らしても、その中での検索には依然としてインデックスが重要である、という役割分担を理解しておくことが、Day21 後半で具体的な定義方法や注意点に進むための土台になる。
