EXPLAINを利用したSQLチューニング

Tag:

EXPLAINを利用したSQLチューニングについて紹介します。

検証テーブル

下記テーブルを例に説明します。

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

testdbというDB上にtable_a、table_bというテーブルを作成し、それぞれ1万件のテストデータを挿入しています。両テーブルともまだインデックスが作られいません。

相関サブクエリは遅い

まず、下記2つのSQLクエリの処理を確認してみます。

1. 結合を利用

SELECT table_b.*, table_a.codeA
FROM table_b
LEFT JOIN table_a
ON table_b.table_a_id = table_a.id

2. 相関サブクエリを利用

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を使ってクエリの実行計画を確認していきます。

1. 結合を利用したクエリの実行計画

EXPLAIN
SELECT table_b.*, table_a.codeA
FROM table_b
LEFT JOIN table_a
ON table_b.table_a_id = table_a.id
explain_join1

2. 相関サブクエリを利用したクエリの実行計画

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
explain_subquery1

keyがNULLになっていますね。つまり、全レコードが評価対象になっています。

インデックスを作成

全レコードが評価対象にならないようにするため、インデックスを次のように作成します。

ALTER TABLE `testdb`.`table_a` ADD INDEX  (`id`)

再度、EXPLAINを使ってクエリの実行計画を確認します。

1. 結合を利用したクエリの実行計画

explain_join2

2. 相関サブクエリを利用したクエリの実行計画

explain_subquery2

keyが利用されていますね。実行時間は次のようになりました。
結合を利用した場合 ⇒ 0.0007 秒
相関サブクエリを利用 ⇒ 0.0006 秒

簡単でしたが、EXPLAINを利用したSQLチューニングの紹介でした。常にEXPLAINでSQLの実行計画を確認する習慣をつけると良いかと思います。

補足:複数のインデックス候補があるとき

複数のインデックス候補があるときには、カーディナリティの高いカラムを優先してインデックスをつけます。

カーディナリティとは、「キーの値の数」と「全レコード数」の比率のことです。リレーションシップのカーディナリティ(1対多など)とは、また別の意味です。

例えば、「男」「女」の値をとる性別カラムより、都道府県カラムのほうが、とりうるデータの種類が多いため、カーディナリティが高いといえます。

スポンサーリンク