MariaDB講座 / EXPLAINを読み、インデックス前後の計画を比較する

EXPLAINは最適化器が選んだ実行計画を表示します。同じ問い合わせと結果をインデックス前後で比較し、アクセス方法や推定行数を、実測時間や実際の出力件数と混同しないように読みます。

計画の項目を文脈と一緒に読む

項目 意味と注意
table その段階でアクセスする表または別名
type アクセス方法。小表のALLが必ず悪いわけではない
possible_keys / key 候補と実際に選択した索引
rows そのアクセス段階の推定。結果の正確な件数ではない
Extra 絞り込み、並べ替え、カバリングなどの追加情報

Using filesortという語だけでディスクファイルのソートと断定しません。表規模、選択割合と実際の待ちを見ます。候補索引は設計、遅いSQLの発見はログ設定とつなげます。

再現可能な1000行を作る

shopcourseへ接続し、digits_40_labとexplain_40_labが未使用か調べます。以下は三つの10数字を組み合わせる完全な例です。

USE shopcourse;
CREATE TABLE digits_40_lab(n TINYINT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO digits_40_lab VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
CREATE TABLE explain_40_lab(
 order_id INT PRIMARY KEY,customer_id INT NOT NULL,
 ordered_at DATETIME NOT NULL,amount DECIMAL(10,2) NOT NULL
) ENGINE=InnoDB;
INSERT INTO explain_40_lab
SELECT 1+a.n+10*b.n+100*d.n,
 MOD(a.n+10*b.n+100*d.n,100)+1,
 DATE_ADD('2026-01-01',INTERVAL (a.n+10*b.n+100*d.n) MINUTE),1000
FROM digits_40_lab a CROSS JOIN digits_40_lab b CROSS JOIN digits_40_lab d;

COUNT(*)が1000か確認します。顧客1~100へ各10注文となる人工分布で、本番の偏りや負荷を再現したものではありません。

同じEXPLAINを作成前後で比べる

索引の前に実行します。

EXPLAIN SELECT order_id,ordered_at FROM explain_40_lab
WHERE customer_id=47 AND ordered_at>='2026-01-01'
ORDER BY ordered_at,order_id;

索引を作り、同じ問い合わせで確認します。

CREATE INDEX idx_e40_customer_date
ON explain_40_lab(customer_id,ordered_at,order_id);
EXPLAIN SELECT order_id,ordered_at FROM explain_40_lab
WHERE customer_id=47 AND ordered_at>='2026-01-01'
ORDER BY ordered_at,order_id;

実際のkey、typeと推定rowsを読みます。この教材のMariaDB 12.3.3による検証記録では、前はALL・keyなし・rows 1000・Using where; Using filesort、後はrange・idx_e40_customer_date・rows 10・Using where; Using indexでした。版、統計とデータにより同じ数値にならない場合があります。推定1000から10を、100倍の実測高速化とは呼びません。

実結果を別に確認する

同じSELECTを実行します。

SELECT order_id,ordered_at FROM explain_40_lab
WHERE customer_id=47 AND ordered_at>='2026-01-01'
ORDER BY ordered_at,order_id;

47から947まで100刻みの十IDです。索引前後で同じ行・同じ順かを照合します。計画は待ち時間を保証しないため、計測では問い合わせ、データ、キャッシュ、同時負荷と繰り返し条件をそろえます。小さな人工例からサービス全体の改善率を作りません。

実行するANALYZEと統計更新を分ける

MariaDBのANALYZEは問い合わせを実行して情報を取得します。UPDATEやDELETEへ無害なEXPLAIN感覚で付けないでください。次はこの学習用SELECTだけを対象にします。

ANALYZE FORMAT=JSON
SELECT order_id,ordered_at FROM explain_40_lab
WHERE customer_id=47 AND ordered_at>='2026-01-01'
ORDER BY ordered_at,order_id;

JSONのr_rowsやr_loopsは実行情報で、推定rowsと区別します。時間に固定の正解値はありません。ANALYZE TABLEは別の統計更新操作で、版による費用やロックも考えます。統計が古い場合も、FORCE INDEXで期待計画へ押す前に構造と分布を調べます。

証拠を残して実習を終える

版、定義、索引、データ生成方法、比較SQLと前後計画を保存します。必要なデータがないことを確認し、他の注文表を含めず、この記事の二表だけを削除します。

DROP TABLE shopcourse.explain_40_lab;
DROP TABLE shopcourse.digits_40_lab;

関連する公式リファレンス