【入門編】 関数インデックス (Expression Index) – PostgreSQL

こんにちは!データベースの世界へようこそ。

普段、本や資料を探すとき、みなさんはどうしていますか?もし図書館の蔵書がすべてバラバラに積み上げられていたら、目当ての一冊を見つけるのに何時間もかかってしまいますよね。

データベースにおける「インデックス(索引)」は、まさに図書館の目録のようなものです。これがあるおかげで、私たちは一瞬で目的のデータにたどり着けるわけです。

でも、たまに「普通の方法では検索がうまくいかない」という厄介なケースに遭遇します。今日はそんな悩みをスッキリ解決してくれる、PostgreSQLの「関数インデックス」という裏技についてお話ししますね。

—

普通のインデックスが「お手上げ」になる瞬間

例えば、ユーザーのメールアドレスを保存しているテーブルがあるとします。会員登録画面で「メールアドレスを入力してください」と案内しても、ユーザーさんは「Example@Gmail.com」と書いたり「example@gmail.com」と書いたりと、大文字と小文字を混ぜて入力することがありますよね。

システム側で「このユーザーは登録済みかな?」と探すとき、こんなクエリを書くことがよくあります。

SELECT FROM users WHERE LOWER(email) = ‘example@gmail.com’;

`LOWER()` という関数は、すべてのアルファベットを小文字に変換してくれる魔法のツールです。これを使えば、大文字・小文字の区別なく検索できます。

でも、ここで問題が。普通のインデックスは「そのままの値」を並べて整理整頓するものです。`LOWER(email)` という「変換後の値」まではインデックスの中に並んでいません。

結果として、データベースは「えっと、変換した後の値を知らないから、全部の行を端から順番にチェックするしかないな…」と、ものすごく時間がかかる作業(全件走査)を始めてしまうんです。これでは、ユーザーが増えるほどサイトが重くなってしまいますよね。

—

そこで登場!「関数インデックス」という切り札

こんなとき、「じゃあ、最初から『小文字に変換した状態』でインデックスを作っちゃえばいいんじゃない?」という天才的な発想が、関数インデックスです。

PostgreSQLでは、こんなふうに指示を出せます。

CREATE INDEX idx_users_lower_email ON users (LOWER(email));

こうすると、PostgreSQLは裏側で「メールアドレスを小文字に変換したリスト」を別途作って保持してくれます。

検索するときは、データベースはもう迷いません。「`LOWER(email)` のインデックスがあるね。じゃあ、そこに答えが書いてあるはずだ!」と、一瞬で目的の行を探し当ててくれるようになります。

—

日常で例えるとこんな感じ

これって、「辞書の索引」を「読み方(ひらがな)」で作り直すことに似ています。

もし、漢字の辞書を「画数順」だけで引くようになっていたら、読み方がわからない漢字を探すのは地獄ですよね。でも、「読み方順の索引」があれば、画数がわからなくても一発で引ける。関数インデックスは、まさに「目的に合わせた専用の索引」をもう一つ作るようなイメージなんです。

こんな場面でも大活躍します!

大文字・小文字の変換以外にも、こんなシーンで役立ちますよ。

  • JSONの中身を検索する: 最近よく使うJSONB形式のデータで、「このJSONの中にある『order_id』というキーの値だけで検索したい!」というとき、その値に関数インデックスを張れば爆速になります。
  • 日付の「年」だけ取り出す: 「2023年のデータだけ全部ほしい!」というとき、`EXTRACT(YEAR FROM created_at)` という式に関数インデックスを張れば、過去何年分あっても即座に抽出できます。

—

最後に:使いすぎには注意!

「便利だから全部インデックスにしちゃえ!」と思うかもしれませんが、ここでちょっとした注意点を。

インデックスは、新しくデータが増えるたびに「作り直し」のコストがかかります。関数インデックスをたくさん作りすぎると、データの追加や更新が少しだけ遅くなってしまうんです。

「よく検索するけど、なかなか見つからない!」という、まさにそのピンポイントな場所にだけ魔法をかけてあげる。これが、熟練エンジニアのスマートなやり方です。

ぜひ皆さんのプロジェクトでも、検索が遅い場所を見つけたら「あ、ここは関数インデックスが使えるかも?」と思い出してみてくださいね。

それでは、また次回の記事でお会いしましょう!Happy Coding!

コメント

タイトルとURLをコピーしました