EXPLAINを利用するとクエリの実行計画を確認することができます。遅いクエリをチューニングする際に活躍します。
検証テーブル
下記テーブルを例に説明します。
table_a
id | codeA |
---|---|
1 | i+Pc_RBu |
2 | 4dDTZ543 |
3 | uE7qK_Ve |
(省略) | |
10000 | P)_3d14V |
table_b
id | codeB | table_a_id |
---|---|---|
1 | 6UxiNqqo | 6821 |
2 | dD+>70E0 | 2847 |
3 | $+HRjlbY | 7963 |
(省略) | ||
10000 | Zq7mKwSF | 8683 |
table_a、table_bというテーブルを作成し、それぞれ1万件
のテストデータを挿入しています。両テーブルともまだインデックスが作られいません。
相関サブクエリは遅い
まず、下記2つのSQLクエリの処理を確認してみます。
-- 結合を利用
SELECT table_b.*, table_a.codeA
FROM table_b
LEFT JOIN table_a
ON table_b.table_a_id = table_a.id
-- 相関サブクエリを利用
SELECT table_b.*, (SELECT table_a.codeA
FROM table_a
WHERE table_a.id = table_b.table_a_id) as codeA
FROM table_b
2つのSQLクエリの結果は同じですが、実行時間に大きな差がありました。
結合を利用した場合 ⇒ 0.0276 秒
相関サブクエリを利用 ⇒ 0.1154 秒
相関サブクエリの計算量は次のようになります。
⇒ 外部クエリでフェッチされる件数
× サブクエリでフェッチされる件数
計算量が多くなってしまいがちなので、相関サブクエリを利用しない方法を検討したほうが良いかと思います。
EXPLAINによる実行計画の確認
EXPLAINを使ってクエリの実行計画を確認していきます。
結合を利用したクエリ
EXPLAIN
SELECT table_b.*, table_a.codeA
FROM table_b
LEFT JOIN table_a
ON table_b.table_a_id = table_a.id
相関サブクエリを利用したクエリ
EXPLAIN
SELECT table_b.*, (SELECT table_a.codeA
FROM table_a
WHERE table_a.id = table_b.table_a_id) as codeA
FROM table_b
keyがNULL
になっていますね。つまり、全レコードが評価対象になっています。
インデックスを作成
全レコードが評価対象にならないようにするため、インデックスを次のように作成します。
ALTER TABLE `testdb`.`table_a` ADD INDEX (`id`);
インデックス作成後の実行計画
再度、EXPLAINを使ってクエリの実行計画を確認します。
結合を利用したクエリ
相関サブクエリを利用したクエリ
keyが利用されていますね。実行時間は次のようになりました。
結合を利用した場合 ⇒ 0.0007 秒
相関サブクエリを利用 ⇒ 0.0006 秒
簡単でしたが、EXPLAINを利用したSQLチューニングの紹介でした。常にEXPLAINでSQLの実行計画を確認する習慣をつけると良いかと思います。
補足|複数のインデックス候補があるとき
複数のインデックス候補があるときには、カーディナリティの高いカラムを優先してインデックスをつけます。
カーディナリティとは、キーの値の数
と全レコード数
の比率のことです。リレーションシップのカーディナリティ(1対多など)とは、また別の意味です。
例えば、「男」「女」の値をとる性別カラムより、都道府県カラムのほうが、とりうるデータの種類が多いため、カーディナリティが高いといえます。