Agile育成ブログ
未来を変える喜びを
未分類

SQLのパフォーマンス

1. インデックスの正体は「整理された辞書」

インデックスとは、本の後ろにある索引や辞書のように、データが特定の順番で並んでいる状態を指します。

データベースはこの「並び順」を利用して、「2023-10-01」というデータがどこにあるかを、二分探索などの効率的な方法で瞬時に見つけ出します。

2. なぜ「関数」を使うと遅いのか(イメージ図)

関数を使うということは、「辞書の中身をすべて書き換えてから探す」という作業をデータベースに強いることになります。

❌ 関数あり:TRUNC(created_at) の場合

データベースは、インデックス(索引)に書かれている元の値をそのまま使えなくなります。

元のデータ(索引)TRUNC関数適用後(計算が必要)判定
2023-10-01 10:00→ 2023-10-01一致!
2023-10-01 15:30→ 2023-10-01一致!
2023-10-02 09:00→ 2023-10-02不一致

なぜ遅い?: 上の図のように、すべての行を一行ずつ取り出し、関数で計算し直してから比較しなければなりません。これをフルテーブルスキャン(全件走査)と呼びます。100万件あれば、100万回計算することになり、非常に時間がかかります。

3. なぜ「範囲指定」は速いのか

⭕ 範囲指定:created_at >= '2023-10-01' の場合

こちらは、インデックスの「並び順」をそのまま活用できます。

  1. インデックスの中から「2023-10-01 00:00:00」が始まる場所をピンポイントで探す(一瞬)。
  2. そこから「2023-10-02 00:00:00」の手前までを順番に読み取るだけ(非常に速い)。
処理ステップ動作イメージ
ステップ1索引の「2023-10-01」のページをパッと開く
ステップ2次の日のデータが出てくるまで、連続してデータを拾う
結果必要な行だけしか触らないので爆速

1. インデックスと関数の関係(なぜ使えないのか)

インデックスは、あらかじめ特定の列を「並び替えて保存したリスト」です。

例えば、created_at(登録日)にインデックスがある場合、DB内では以下のように整列しています。

インデックス(整列済み)ポインタ(実際のデータの場所)
2023-10-01 10:00:00[データA]
2023-10-01 15:00:00[データB]
2023-10-02 09:00:00[データC]

関数を使うとどうなるか?

WHERE TRUNC(created_at) = '2023-10-01' と書いた瞬間、DBはこう考えます。

「インデックスには『10:00:00』とか細かい時間が入っているな…。でもユーザーは『TRUNC(切り捨て)した後の値』で探せと言っている。インデックスの中身を全部計算し直さないと、どれが一致するか分からないぞ!

結果として、DBはせっかく並び替えたインデックスを使わずに、テーブルの端から端まで全部チェック(フルスキャン)し始めてしまいます。