MySQL の COVERING INDEX でディスクI/Oを削減する

通常のインデックス検索では、インデックスで行を特定した後、テーブル本体からデータを取得します。しかし、クエリで必要なカラムがすべてインデックスに含まれていれば、テーブル本体へのアクセスを省略できます。これを「カバリングインデックス」と呼びます。

カバリングインデックスの仕組み

通常のインデックス検索とカバリングインデックスの違いを見てみましょう。

通常のインデックス検索

インデックスで行を特定 → テーブル本体から全カラム取得(ランダムI/O発生)

カバリングインデックス

インデックスだけで必要なカラムをすべて取得(テーブルアクセス不要)

ディスク I/O が減るため、特に大量データの検索で効果を発揮します。

カバリングインデックスの確認方法

EXPLAIN の Extra 列に Using index と表示されれば、カバリングインデックスが使われています。

-- インデックス: (user_id, status)
EXPLAIN SELECT user_id, status FROM orders WHERE user_id = 100;

この場合、user_idstatus はどちらもインデックスに含まれているため、テーブル本体を参照せずに結果を返せます。

Extra: Using indexカバリングインデックス使用
Extra: NULL(Using index なし)テーブル本体へのアクセスあり

カバリングインデックスの作り方

クエリで取得するカラムをすべてインデックスに含めます。

-- このクエリをカバリングインデックスで高速化したい
SELECT user_id, email, created_at FROM users WHERE status = 'active';

-- カバリングインデックスを作成
ALTER TABLE users ADD INDEX idx_covering (status, user_id, email, created_at);

WHERE 句のカラム(status)を先頭に、SELECT するカラムをその後に配置します。

効果が大きいケース

カバリングインデックスは、以下のような場合に特に効果的です。

大量の行を取得するクエリ

テーブル本体へのランダムアクセスが減るため、I/O 削減効果が大きくなります。

ディスクが遅い環境

SSD より HDD 環境で効果が顕著です。ランダム I/O のコストが高いためです。

集計クエリ

COUNT や SUM で大量行を処理する場合、テーブルアクセスなしで計算できます。

具体例: COUNT の高速化

ユーザーごとの注文数をカウントするケースを考えます。

SELECT user_id, COUNT(*) as order_count 
FROM orders 
GROUP BY user_id;

(user_id) のインデックスがあれば、テーブル本体を見ずにカウントできます。

ALTER TABLE orders ADD INDEX idx_user_id (user_id);

EXPLAIN で Using index が表示されていれば成功です。

注意点とトレードオフ

カバリングインデックスは万能ではありません。

メリットデメリット
ディスク I/O 削減インデックスサイズ増大
クエリ高速化更新・挿入が遅くなる
メモリ効率向上メンテナンス対象増加

インデックスにカラムを追加するほど、インデックス自体のサイズが大きくなります。書き込み性能への影響も考慮が必要です。

SELECT * を避ける理由

カバリングインデックスを活用するには、SELECT * を避けることが重要です。

-- カバリングインデックス使えない
SELECT * FROM orders WHERE user_id = 100;

-- カバリングインデックス使える可能性
SELECT user_id, status, created_at FROM orders WHERE user_id = 100;

必要なカラムだけを取得する習慣をつけることで、カバリングインデックスの恩恵を受けやすくなります。

InnoDB の特性

InnoDB では、セカンダリインデックスに主キーの値が自動的に含まれます。これを利用すると、主キーを明示的にインデックスに追加しなくてもカバリングインデックスとして機能することがあります。

-- 主キー: id
-- セカンダリインデックス: (status)
-- 実際のインデックス構造: (status, id)

SELECT id, status FROM users WHERE status = 'active';
-- id は自動で含まれているため Using index になる

まとめ

クエリで使うカラムを特定

WHERE 句のカラムを先頭にしたインデックス作成

SELECT するカラムもインデックスに追加

EXPLAIN で Using index を確認

カバリングインデックスは、読み取り中心のワークロードで特に有効です。ただし、インデックスの肥大化と更新性能への影響を考慮して、本当に必要な場所にだけ適用しましょう。