導入
データベース運用において、「検索が遅い」という課題は避けて通れません。テーブルのデータ量が増大するにつれ、フルテーブルスキャン(全件走査)が発生すると、レスポンスタイムが劇的に悪化します。この問題を解決する最も基本的かつ強力な手段が「インデックス(索引)」の活用です。適切にインデックスを設計することで、クエリの実行速度を劇的に改善し、システム全体のパフォーマンスを最適化できます。
基礎知識
インデックスとは、テーブル内の特定の列の値を抜き出し、検索を効率化するために独自のデータ構造で整理したものです。例えるなら、教科書の巻末にある「索引」のようなものです。本来は先頭から最後までページをめくって探す必要がある情報も、索引を使えば目的のページへ一瞬でたどり着けます。
PostgreSQLではデフォルトでB-treeインデックスが使用されます。これはデータがソートされた状態で木構造に格納される仕組みで、等値検索(=)や範囲検索(<, >)において非常に高いパフォーマンスを発揮します。
実装/解決策
インデックスを作成する際は、CREATE INDEX文を使用します。基本構文は「CREATE INDEX インデックス名 ON テーブル名 (列名);」です。
実務においては、単に作成するだけでなく「どの列に貼るか」の見極めが重要です。WHERE句で頻繁に使用される列や、JOIN句で使用する外部キーなどが主な対象となります。ただし、インデックスを無闇に増やすと、データの更新(INSERT/UPDATE/DELETE)時にインデックスの再構築コストが発生し、書き込み性能が低下するため注意が必要です。
サンプルプログラム
以下のSQLは、ユーザーテーブルに対して特定の列にインデックスを付与し、確認・削除を行う手順です。
-- 1. ユーザーテーブルのメールアドレス列にインデックスを作成 -- 検索頻度が高い列に付与することで、検索速度を向上させます CREATE INDEX idx_users_email ON users (email); -- 2. 作成されたインデックスを確認する(psqlコマンドなどでも確認可能) -- インデックスの一覧を表示して、正しく作成されているか確認します SELECT relname AS index_name FROM pg_class WHERE relkind = 'i' AND relname = 'idx_users_email'; -- 3. 不要になったインデックスを削除する -- パフォーマンスに寄与していない、あるいは更新負荷が高い場合は削除を検討します DROP INDEX idx_users_email;
応用・注意点
現場でインデックスを扱う際の重要なポイントをいくつか挙げます。
1. 不要なインデックスの排除
使用されていないインデックスは、メモリとディスク容量を消費するだけでなく、更新処理のボトルネックになります。定期的に「pg_stat_user_indexes」ビューを確認し、一度もスキャンされていないインデックスがあれば削除を検討してください。
2. 複合インデックスの順序
複数の列を組み合わせた複合インデックスを作成する場合、左側の列から順に評価される特性があります。WHERE句でよく使用される列を先頭(左側)に配置するように設計してください。
3. CONCURRENTLYの使用
本番環境で大規模なテーブルにインデックスを作成する場合、通常のCREATE INDEXだとテーブルがロックされ、サービスが停止する可能性があります。PostgreSQLでは「CREATE INDEX CONCURRENTLY」を使用することで、テーブルをロックせずにインデックスを作成できます。時間はかかりますが、稼働中のシステムでは必須のテクニックです。

コメント