はじめに
- 業務をする上で良く忘れる場合があるため、まとまったメモとして残してます
- 周囲に教える際の参考資料のためでもあります
- 前提条件など結構すっ飛ばしております
スロークエリとは
- SQLを実行する際に予めMySQLにて設定された実行結果までのタイムを越えたクエリ
- MySQLの設定でログとして出力することができる
# Time: 110723 13:22:02
# User@Host: root[root] @ localhost []
# Query_time: 7.677186 Lock_time: 0.156390 Rows_sent: 1 Rows_examined: 1386155
use hoge_db;
SET timestamp=1311394922;
SELECT count(*) FROM `hoge_table` WHERE (hoge_time between '2011-07-19 18:00:00' AND '2011-07-19 19:00:00') AND (hoge_id = 1) AND (hage_id = '1');
- 1行目 記録日時
- 2行目 ユーザーIDとリクエストした端末
- 3行目 Query_time(実行時間) Lock_time(ロック時間) Rows_sent(送信行数)
Rows_examined(処理対象となった行数) - 4行目 SQL文
EXPLAINとは
- スロークエリを最適化する際に、どのように最適化すれば良いかをMySQLが教えてくれるコマンド
- 主に見るべきところとしてはtype、rows、
mysql> EXPLAIN SELECT * FROM hoge;
+----+-------------+----------+------+---------------+------+---------+------+-------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+------+---------------+------+---------+------+-------+-------+
| 1 | SIMPLE | hoge | ALL | NULL | NULL | NULL | NULL | 46497 | |
+----+-------------+----------+------+---------------+------+---------+------+-------+-------+
type
|#|ステータス名|説明|
|:---|:---|:---|:---|:---|
|1|system|テーブルに1レコードしかない状態|
|2|const|マッチするレコードが1件しかない状態。PRIMARY KEYまたはUNIQUEインデックスを利用して検索される|
|3|eq_ref|JOINにおいてPRIMARY KEYまたはUNIQUEインデックスを利用して1つのレコードを検索している状態|
|4|index|すべてのレコードのインデックスをスキャンする必要がある状態(フルインデックススキャン)|
|5|ALL|すべてのレコードを走査する必要がある状態(フルテーブルスキャン)|
最適化ポイント
- const、eq_ref、rengeは、インデックスを有効に利用できている
- indexはインデックスをフルスキャンしているので遅い。インデックスの見直しが必要
- ALLの場合はテーブルフルスキャン。インデックスもしくはテーブル構成の見直しが必要
row
- クエリによって取得が想定される行数
- 実際に取得された数ではないところに注意が必要
Extra
|#|ステータス名|説明|
|:---|:---|:---|:---|:---|
|1|Using where|WHERE句に検索条件が指定されており、なおかつインデックスを見ただけではWHERE句の条件を全て適用することが出来ない場合に表示される|
|2|Using index|クエリがインデックスだけを用いて解決できることを示す。Covering Indexを利用している場合に表示される|
|3|Using filesort|メモリ上のバッファでソート処理ができず、テンポラリファイルが作成されてソート処理がされている場合に出力される。SQL文にORDER BY句を指定している場合に表示される|
|4|Using temporary|クエリの実行にテンポラリテーブルが必要な場合に表示される。SQL文がJOINかつORDER BY句を利用している場合やGROUP BY句とORDER BY句で指定しているカラムが異なる場合などで発生することがある|
|5|Using index for group-by|MIN()/MAX()がGROUP BY句と併用されているとき、クエリがインデックスだけを用いて解決できることを示す|
|6|Range checked for each record (index map: N)|JOINにおいてrangeまたはindex_mergeが利用される場合に表示される|
|7|Not exists|LEFT JOINにおいて、左側のテーブルからフェッチされた行にマッチする行が右側のテーブルに存在しない場合、右側のテーブルはNULLとなるが、右側のテーブルがNOT NULLとして定義されたフィールドでJOINされている場合にはマッチしない行を探せば良い・・・ということを示す|