MySQL で不要なインデックスを見つけて削除する

インデックスは検索を速くしますが、多すぎると書き込み性能の低下やディスク容量の浪費につながります。使われていないインデックスを見つけて削除する方法を解説します。

不要なインデックスの影響

インデックスが多すぎると、以下の問題が発生します。

INSERT / UPDATE / DELETE の遅延

データ変更時にすべてのインデックスを更新する必要があるため、書き込みが遅くなります。

ディスク容量の消費

インデックスはデータ本体とは別にストレージを消費します。大量の不要インデックスは無駄なコストです。

オプティマイザの判断ミス

選択肢が多すぎると、最適でないインデックスを選んでしまうことがあります。

使われていないインデックスを見つける

MySQL 5.6 以降では、Performance Schema でインデックスの使用状況を確認できます。

SELECT 
    object_schema AS database_name,
    object_name AS table_name,
    index_name,
    count_read,
    count_write
FROM performance_schema.table_io_waits_summary_by_index_usage
WHERE object_schema = 'your_database'
  AND index_name IS NOT NULL
ORDER BY count_read ASC;

count_read が 0 のインデックスは、一度も読み取りに使われていないことを意味します。

sys スキーマを使う方法

MySQL 5.7 以降では、sys スキーマでより簡単に確認できます。

SELECT * FROM sys.schema_unused_indexes
WHERE object_schema = 'your_database';

このビューは、作成以降一度も使われていないインデックスを一覧表示します。

重複インデックスを見つける

同じカラム、または左端プレフィックスが重複するインデックスは無駄です。

-- 例: 以下は重複
INDEX idx_user (user_id)
INDEX idx_user_status (user_id, status)  -- idx_user は不要

複合インデックス (user_id, status) があれば、(user_id) 単体のインデックスは不要です。MySQL が自動的にプレフィックスとして使います。

sys スキーマで重複インデックスを検出できます。

SELECT * FROM sys.schema_redundant_indexes
WHERE table_schema = 'your_database';

pt-duplicate-key-checker を使う

Percona Toolkit の pt-duplicate-key-checker は、重複・冗長インデックスを検出する専用ツールです。

pt-duplicate-key-checker --host=localhost --user=root --password=xxx --databases=your_database

出力には、削除しても問題ないインデックスと、その ALTER TABLE 文が含まれます。

重複インデックス同一カラムの組み合わせ
冗長インデックス左端プレフィックスが重複

削除前の確認事項

インデックスを削除する前に、以下を確認してください。

Performance Schema の統計はサーバー起動後からのデータ
月次バッチなど低頻度のクエリで使われている可能性
外部キー制約で必要とされていないか
将来的に使う予定がないか

サーバー再起動で統計はリセットされるため、十分な期間(少なくとも1ヶ月程度)運用してから判断しましょう。

インデックスの削除方法

不要と判断したら、DROP INDEX で削除します。

ALTER TABLE orders DROP INDEX idx_unused;
-- または
DROP INDEX idx_unused ON orders;

大きなテーブルでは、オンライン DDL で削除できますが、それでも負荷がかかることがあります。低負荷な時間帯に実施することをおすすめします。

削除を迷うときの対処法

削除するか迷う場合は、INVISIBLE INDEX 機能(MySQL 8.0以降)を使えます。

-- インデックスを不可視にする
ALTER TABLE orders ALTER INDEX idx_maybe_unused INVISIBLE;

-- 問題があれば元に戻す
ALTER TABLE orders ALTER INDEX idx_maybe_unused VISIBLE;

不可視インデックスはオプティマイザから見えなくなりますが、データは維持されます。これで影響を確認してから、本当に削除するか判断できます。

定期的なメンテナンス

インデックスの見直しは一度きりではなく、定期的に行うべきです。

四半期ごとに未使用インデックスを確認

重複インデックスをチェック

INVISIBLE にして影響確認

問題なければ削除

アプリケーションの変更でクエリパターンが変わると、必要なインデックスも変わります。継続的なメンテナンスがパフォーマンス維持の鍵です。