11.

DB2 CREATE INDEX 構文|UNIQUE / 複合 / 降順 / INCLUDE の使い方

編集
この記事の要点
  • DB2 でインデックスを作成する SQL 構文
  • 基本: CREATE INDEX 名 ON テーブル名 (列1, 列2);
  • UNIQUE インデックス: CREATE UNIQUE INDEX ... — 重複を許さない
  • 降順: CREATE INDEX ix ON t (col DESC);
  • INCLUDE 句で非キー列を含める(カバリングインデックス)— 検索性能 +α
  • 貼りすぎると INSERT/UPDATE が遅くなる。WHERE / ORDER BY / JOIN で頻繁に使う列に絞る

基本構文

-- 単一列インデックス
CREATE INDEX idx_users_email ON users (email);

-- 複合インデックス(左から評価される)
CREATE INDEX idx_orders_user_date ON orders (user_id, order_date);

-- UNIQUE(重複不可。実質ユニーク制約)
CREATE UNIQUE INDEX idx_users_email_uniq ON users (email);

-- 降順
CREATE INDEX idx_orders_date_desc ON orders (order_date DESC);

-- 複数の昇降混合
CREATE INDEX idx_logs ON access_logs (user_id ASC, accessed_at DESC);

INCLUDE 句(カバリングインデックス)

DB2 はインデックスに非キー列を含める INCLUDE 句をサポート。検索条件には使わないが SELECT に含めたい列を入れることで、テーブル本体を読まずに済むようになります:

-- email で検索したついでに name と age を取りたいケース
CREATE UNIQUE INDEX idx_users_cover
ON users (email)
INCLUDE (name, age);

-- このクエリがインデックスだけで完結する(テーブルアクセスなし)
SELECT name, age FROM users WHERE email = ?;

インデックスの確認・削除

-- システムカタログから一覧
SELECT TABNAME, INDNAME, COLNAMES
FROM SYSCAT.INDEXES
WHERE TABSCHEMA = 'MYSCHEMA';

-- 特定テーブルのインデックス確認
SELECT INDNAME, UNIQUERULE, COLNAMES
FROM SYSCAT.INDEXES
WHERE TABNAME = 'USERS';

-- インデックス削除
DROP INDEX idx_users_email;

-- インデックスのリビルド(断片化解消)
REORG INDEXES ALL FOR TABLE users;

複合インデックスの「左から評価」ルール

CREATE INDEX ix ON orders (user_id, order_date) がある場合:

クエリインデックス使用
WHERE user_id = 1○ 使われる(先頭列)
WHERE user_id = 1 AND order_date = '2024-01-01'○ 完全に使われる
WHERE user_id = 1 ORDER BY order_date○ ソートにも使える
WHERE order_date = '2024-01-01'× 使われない(先頭列なし)
WHERE user_id LIKE '1%'○ 前方一致は使われる
WHERE user_id LIKE '%1'× 後方一致は使えない

EXPLAIN(実行計画)で使われているか確認

-- DB2 の EXPLAIN PLAN
EXPLAIN PLAN FOR
SELECT * FROM users WHERE email = 'foo@example.com';

-- 結果を見る
SELECT OPERATOR_TYPE, OBJECT_NAME, TOTAL_COST
FROM EXPLAIN_OPERATOR
ORDER BY OPERATOR_ID;

-- ツール経由なら db2expln コマンドが便利
-- db2expln -d MYDB -q "SELECT * FROM users WHERE email = '?'"

インデックスを貼るべき列の選び方

条件インデックス効果
WHERE で頻繁に使う○ 最重要
JOIN の結合キー○ 大幅な性能改善
ORDER BY / GROUP BY の対象列○ ソート省略可能
カーディナリティ(種類数)が高い列○ ユニーク値が多い列ほど効く
性別など 2 値しかない列× ほぼ無意味
UPDATE 頻度が高い列△ INSERT/UPDATE 性能が落ちる
NULL が多い列△ DB2 はデフォルトで NULL を含めるが、NOT NULL 列の方が効率的

注意点

  • INSERT / UPDATE / DELETE が遅くなる: インデックス更新のオーバーヘッド。1 テーブル 5 個前後が目安
  • ディスク容量を消費: 大きなテーブルでは数百 MB〜数 GB
  • 断片化: 大量更新後は REORG INDEXES を定期実行
  • 使われないインデックス: MON_GET_INDEX で利用統計を取り、未使用なら削除
  • 主キー / UNIQUE 制約は自動でインデックスが作られる — 二重で貼らない

他 DBMS との CREATE INDEX の違い

機能DB2OracleMySQLPostgreSQL
基本CREATE INDEXCREATE INDEXCREATE INDEXCREATE INDEX
UNIQUEUNIQUEUNIQUEUNIQUEUNIQUE
降順DESCDESCDESC (8.0+)DESC
INCLUDE 句××○ (11+)
関数インデックス○ (10.5+)○ (8.0+)
部分インデックス△ (関数で代用)×○ (WHERE 句)

関数インデックス(DB2 10.5+)

-- 大文字小文字を無視した検索を高速化
CREATE INDEX idx_email_upper ON users (UPPER(email));

-- このクエリで idx_email_upper が使われる
SELECT * FROM users WHERE UPPER(email) = UPPER('Foo@Example.com');

-- 日付の年だけを索引化
CREATE INDEX idx_year ON orders (YEAR(order_date));
SELECT * FROM orders WHERE YEAR(order_date) = 2024;

運用

  • RUNSTATS を忘れず: インデックス作成後は RUNSTATS ON TABLE users WITH DISTRIBUTION AND DETAILED INDEXES ALL で統計情報を更新(オプティマイザがインデックスを使うか判断するため)
  • 本番作成は CONCURRENT: 大テーブルなら CREATE INDEX ... ALLOW WRITE ACCESS でロックを最小化
  • 定期 REORG: インデックスは断片化するので月次〜四半期で REORG

関連

  • パーティション索引: 大規模テーブルではパーティションごとに索引を持つ設計が有効
  • クラスタード索引: CREATE INDEX ... CLUSTER でテーブル物理配置を索引順に近づける
  • テキスト索引: 全文検索なら CREATE INDEX ... USING DB2 TEXT
編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. DB接続コマンド
  2. データベース一覧の確認
  3. テーブル一覧の確認
  4. テーブル定義の確認
  5. DBの設定確認
  6. テーブルスペースの容量の確認および拡張
  7. データ型
  8. 複数カラムのUPDATE
  9. カラムの追加/削除/変更
  10. 自動番号付け (autoincrement) する方法
  11. インデックスの作成
  12. シーケンスおよびインクリメント(ID列)の違いと確認方法
  13. create table文の生成
  14. 特定スキーマの全テーブルの全カラム情報を取得する方法
  15. 【DB2】エラー一覧
  16. 【DB2】テーブル定義からCREATE TABLE文を生成する方法