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 制約は自動でインデックスが作られる — 二重で貼らない

関連

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

他 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
編集
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文を生成する方法