【入門編】 関数ベースのインデックス – PostgreSQL

こんにちは!データベースエンジニアの技術ブログへようこそ。

今日は、PostgreSQLを使っていると必ずと言っていいほど直面する「検索が遅い!」という悩みについて、ちょっと面白い解決策をお話ししますね。

データベースのインデックス(索引)といえば、辞書の「目次」のようなものだと聞いたことはありませんか? まさにその通りなのですが、実はこの目次、「そのままの形」でしか探せないという少し頑固な一面があるんです。

どういうことか、一緒に紐解いていきましょう。

—

辞書から「小文字」を探したいとき、何が起きる?

たとえば、ユーザー登録名がズラリと並んだリストがあるとします。
「田中」「tanaka」「TANAKA」……。これらがバラバラに登録されているデータベースから、ユーザーが検索窓に「tanaka」と入力したとき、全部ヒットさせたいですよね。

そんなとき、私たちはよくこう書きます。

`SELECT FROM users WHERE LOWER(name) = ‘tanaka’;`

「名前を全部小文字(LOWER)に変換してから、’tanaka’ と一致するものを見つけてね!」という命令です。

でも、データベース側は困ってしまいます。なぜなら、データベースが持っているインデックスは「元々の名前(田中、tanaka…)」を基準に作られているからです。「小文字に変換した後の名前」なんて、インデックスには書いていないんですよ。

結果として、データベースは仕方なく最初から最後まで全ての行を目視チェックする「フルスキャン」という重労働を強いられます。これが、検索が遅くなる最大の原因です。

「関数ベースのインデックス」という裏技

ここで登場するのが、今回の主役「関数ベースのインデックス」です。

これは簡単に言うと、「計算済みの結果を、あらかじめ索引帳に書き込んでおく」という手法です。

料理の仕込みに例えると…

イメージしてみてください。あなたはレストランのオーナーです。注文が入るたびに野菜を洗って切っていたら、お客様をお待たせしてしまいますよね?
そこで、あらかじめ「カット済み野菜」のストックを用意しておくことにしました。これなら、注文が入った瞬間にパッと出せますよね。

関数ベースのインデックスは、まさにこれです。

「小文字に変換した状態」をあらかじめ計算しておいて、それを索引帳の別枠として作っておくんです。そうすれば、`LOWER(name)` という検索条件が来たとき、データベースは「あ、これなら計算済みリストに書いてあるぞ!」と即座に答えを見つけ出せるようになります。

どうやって書くの?

PostgreSQLでこれを実装するのは驚くほど簡単です。普段のインデックス作成コマンドに、ちょっと計算式を混ぜるだけ。

CREATE INDEX idx_users_lower_name ON users (LOWER(name));

たったこれだけ!
これだけで、データベースは `LOWER(name) = ‘…’` という検索条件を見るたびに、この専用の索引帳を使って爆速で検索してくれるようになります。

注意点も、少しだけ

とても便利な機能ですが、一つだけ覚えておいてほしいことがあります。それは「何でもかんでもインデックスを作らないこと」です。

  • 書き込みが少し遅くなる: データが増えるたびに「計算後の値」も保存し直さないといけないので、データの更新頻度が高いテーブルでは少し負荷になります。
  • ストレージ容量を使う: 索引帳が分厚くなるので、ディスク容量を少し多めに消費します。

「よく検索するけど、更新はそこまで頻繁じゃない」という場所にこそ、このテクニックは輝きます。

—

最後に

データベース設計は、まるで図書館の整理整頓のようなものです。「どういう風に検索されるかな?」と想像しながら、適切な索引を用意してあげる。そうすると、データベースは期待に応えて、驚くほど軽快に動いてくれるようになります。

もし今、あなたのサービスで「検索が重いな」と感じている箇所があったら、ぜひこの「関数ベースのインデックス」を思い出してみてください。

皆さんのデータベースが、今日も快適に動きますように!それでは、また次回の記事でお会いしましょう。

コメント

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