Post on 24-May-2015
MySQLINDEX+EXPLAIN入門
株式会社インフィニットループ
ota
作成:2011/3/11 最終更新:2011/4/1
このスライドの内容
MySQL5.1 InnoDB を前提とした INDEX と EXPLAIN の初級編
目次
INDEX を使おう
INDEX とは何か
INDEX を使用する時に気をつけること
INDEX を作成する時に気をつけること
EXPLAIN を使おう
EXPLAIN とは何か
EXPLAIN で出力される各項目について
EXPLAIN 出力結果からできる SQL チューニング
INDEXとは何か
テーブルにおける本の索引のようなもの※索引:本の中の語句や事項などを一定の順序(あいうえお順等)に並べ、その語句や事項のあるページを示した表
索引を使わずに目的のページを1ページ目から順番に探す(インデックスを使用しない SELECT)
→ 遅い
索引を使って目的のページを探す (インデックスを使用した SELECT)
→ 早い
※ただし単純な検索の場合、1,000レコード以下ならインデックスがない方が速いことも
INDEXとは何かSELECT 速度比較
0
500
1,000
1,500
2,000
2,500
1 101 201 300
ミリ秒
万レコード
条件項目へのインデックス有り無しで SELECT にかかる時間の違いを調べてみる
SELECT * FROM test_tbl WHERE col_1 = 2000;
※10回毎の平均値
インデックスを使用すると SELECT にかかる時間が件数に比例せず一定
インデックスを使用しないと SELECT にかかる時間が件数に比例して増加する
無し 有り
INDEXを使用する時に気をつけることWHERE句 その1
!=、<>はインデックスが使用できない
WHERE句 の全てのANDにかかっていないインデックスは使用されない
曖昧検索時、定数文字列+前方一致以外ではインデックスが使用できない
WHERE col_index_1 = 1 AND col_index_2 = 2 OR col_index_1 = 3 AND col_index_3 = 4
○ col_index_1 × col_index_2 × col_index_3
○ WHERE col_index_1 LIKE '文字列%' × WHERE col_index_1 LIKE '%文字列' × WHERE col_index_1 LIKE '%文字列%' × WHERE col_index_1 LIKE col_2
× WHERE col_index_1 != 1 ○ WHERE col_index_1 IN (2,3)
キー名 種別 フィールド
col_index_1 INDEX col_index_1
col_index_2 INDEX col_index_2
col_index_3 INDEX col_index_3
INDEXを使用する時に気をつけることWHERE句 その2
複合インデックス
複数のカラムに対するインデックス
先頭のインデックスから順に部分インデックスとして使用できる
※ほとんどの場合MySQL側で適切に並び替えてくれるが、一応先頭インデックスから順に書くこと
WHERE col_index_part_1 = 1 AND col_index_part_2 = 2 AND col_index_part_3 = 3
○ col_index_part_1, col_index_part_2, col_index_part_3
WHERE col_index_part_1 = 1 AND col_index_part_2 = 2
○ col_index_part_1, col_index_part_2
WHERE col_index_part_2 = 1 AND col_index_part_3 = 2
× col_index_part_2, col_index_part_3 × col_index_part_2 × col_index_part_3
キー名 種別 フィールド
col_index_1_2_3 INDEX col_index_part_1
col_index_part_2
col_index_part_3
INDEXを使用する時に気をつけることWHERE句 その3
前のキーが範囲検索の場合、それ以降のキーが使用されないことがある
インデックスマージ
インデックスを結合して利用する
想定通りにインデックスマージとして利用されない可能性がある
WHERE col_index_part_1 > 1 AND col_index_part_2 = 2 AND col_index_part_3 = 3
○ col_index_part_1 × col_index_part_1, col_index_part_2, col_index_part_3
↓ インデックスが使用されるように書き換える ↓
WHERE col_index_part_1 IN (2,3) AND col_index_part_2 = 2 AND col_index_part_3 = 3
○ col_index_part_1, col_index_part_2, col_index_part_3
キー名 種別 フィールド
col_index_1 INDEX col_index_1
col_index_2 INDEX col_index_2
INDEXを使用する時に気をつけることWHERE句 その4
複合インデックスとインデックスマージの違い
使用可能となるインデックス
複合インデックス(col_index_part_1, col_index_part_2)
インデックスマージ(col_index_1, col_index_2の単体インデックス)
○ col_index_part_1○ col_index_part_1, col_index_part_2
○ col_index_part_1○ col_index_part_2○ col_index_part_1, col_index_part_2
キー名 種別 フィールド
col_index_1_2 INDEX col_index_part_1
col_index_part_2
キー名 種別 フィールド
col_index_1 INDEX col_index_1
col_index_2 INDEX col_index_2
INDEXを使用する時に気をつけることWHERE句 その5
使用可能となる条件の一例
複合インデックス
インデックスマージ
○ WHERE col_index_part_1 = 1 AND col_index_part_2 = 2× WHERE col_index_part_1 = 1 OR col_index_part_2 = 2○ WHERE col_index_part_1 = 1 OR col_index_part_1 = 1 AND col_index_part_2 = 2
○ WHERE col_index_1 = 1 AND col_index_2 = 2○ WHERE col_index_1 = 1 OR col_index_2 = 2× WHERE col_index_1 = 1 OR col_index_1 = 1 AND col_index_2 = 2
INDEXを使用する時に気をつけることSELECT 速度比較
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1 101 201 300
ミリ秒
万レコード
条件項目が複合インデックスかインデックスマージかで SELECT にかかる時間の違いを調べてみる
SELECT * FROM test_tbl WHERE col_1 = 2000 AND col_2 = ‘5000’;
※10回毎の平均値
複合:
マージ:
複合インデックスとインデックスマージではインデックスマージの方が遅い
複合 マージ
キー名 種別 フィールド
col_index_1_2 INDEX col_1
col_2
キー名 種別 フィールド
col_index_1 INDEX col_1
col_index_2 INDEX col_2
拡大
以下の場合 ORDER BY句にインデックスは使用できない
連続しないキー
※連続していれば問題ない
ORDER BY col_index_part_1, col_index_part_3
× col_index_part_1 × col_index_part_3 × col_index_part_1,col_index_part_2, col_index_part_3
INDEXを使用する時に気をつけることORDER BY その1
ORDER BY col_index_part_1, col_index_part_2
○ col_index_part_1, col_index_part_2
キー名 種別 フィールド
col_index_1_2_3 INDEX col_index_part_1
col_index_part_2
col_index_part_3
ASC と DESC が混在している
複数のキー
INDEXを使用する時に気をつけることORDER BY その2
ORDER BY col_index_1, col_index_2
× col_index_1 × col_index_2
キー名 種別 フィールド
col_index_1 INDEX col_index_1
col_index_2 INDEX col_index_2
ORDER BY col_index_part_1, col_index_part_2 DESC
× col_index_part_1 × col_index_part_2 × col_index_part_1 , col_index_part_2
キー名 種別 フィールド
col_index_1_2_3 INDEX col_index_part_1
col_index_part_2
col_index_part_3
INDEXを使用する時に気をつけることORDER BY その3
WHERE句 で使用されているものと別のキー
ORDER BY句 と GROUP BY句 で使用している項目が異なる
WHERE col_index_1 = 1ORDER BY col_index_2
△ col_index_1
△ col_index_2
※どちらか片方のみ使用可能
キー名 種別 フィールド
col_index_1 INDEX col_index_1
col_index_2 INDEX col_index_2
GROUP BY col_index_1ORDER BY col_index_2
○ col_index_1 × col_index_2
キー名 種別 フィールド
col_index_1 INDEX col_index_1
col_index_2 INDEX col_index_2
HAVING句 はインデックスが使用されない
使用して欲しいインデックスが使用されない場合は FORCE INDEX を使ってインデックスを指定することができる
想定したインデックスを使用する SQL になっているかを EXPLAIN で確認する
※レコード数やデータの内容により使用されるインデックスが変わる可能性があるので、実際に近いデータを使用することが重要
INDEXを使用する時に気をつけることその他
INDEXを作成する時に気をつけることその1
基本的に選択性の高い項目がインデックスだと効果が高い
選択性が高い → その項目で絞り込んだ結果件数が少ない
選択性が低い → その項目で絞り込んだ結果件数が多い※性別、ON/OFFフラグとして使用する項目など※ほとんどフラグが立っていない項目の、フラグが立っているものを抽出する場合などは 選択性が低くても結果件数が少なくなるためインデックスにすると効果が高い
複合インデックスは先頭から順に部分インデックスとしても使用できるので、単独で使われることもあるカラムはインデックスの最初の列に指定する
複合インデックスは選択性の高いものを先頭にする
INDEXを作成する時に気をつけることその2
インデックスサイズが増えることによる影響
検索速度が低下
INSERT、UPDATE、DELETE時インデックスを作り直す速度が低下
インデックス情報を格納するためDB容量が増加
メモリに収まるサイズを超えると、ディスクからの読み込みが発生して速度が大幅低下
INDEXを作成する時に気をつけることインデックスサイズ比較
0
60
120
180
240
1 101 201 300
MB
万レコード0 1 1(3の複合) 3 データサイズ
インデックスの有り無し、個数でインデックスサイズの違いを調べてみる
0:無し1:
1(3の複合):
3:
インデックスが多い程DBサイズ増加
複数の単体インデックスよりも同項目の複合インデックスの方がDBサイズ少
キー名 種別 フィールド
col_index_1_2_3 INDEX col_1
col_2
col_3
キー名 種別 フィールド
col_index_1 INDEX col_1
col_index_2 INDEX col_2
col_index_3 INDEX col_3
キー名 種別 フィールド
col_index_1 INDEX col_1
INDEXを作成する時に気をつけることINSERT 速度比較
0
1
2
3
4
1 101 201 300
ミリ秒
万レコード0 1 1(3の複合) 3
インデックスの有り無し、個数で INSERT にかかる時間の違いを調べてみる
" INSERT INTO test_tbl (col_1, col_2, col_3, col_4) VALUES (" . rand(0,1000000) . ", " . rand(0,1000000) . "," . rand(0,1000000) . "," . rand(0,1000000) . ") ;"
※10,000回毎の平均値
インデックスが多い方がより時間がかかる
複数の単体インデックスよりも同項目の複合インデックスの方が速い
INDEXを作成する時に気をつけることその3
インデックスサイズを減らすには
不要なインデックスを作成しない
インデックスのキー長を短くする 小さいサイズのデータ型を使用する、長い文字列などをインデックスにしない
データ自体を減らす
EXPLAINとは何か
「EXPLAIN SELECT ~」等 SELECT 文の頭に「EXPLAIN」をつけると、MYSQLオプティマイザがクエリの実行計画を表示してくれる
※DELETE、UPDATEで使用したい場合はSELECTに書き換える
EXPLAIN SELECT * FROM test_tbl WHERE col_index_1 = 1 AND col_index_2 = 2 AND col_index_3 = 3;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE test_tbl ref col_index_1,col_index_2 col_index_1 4 const 1 Using where
EXPLAINで出力される各項目についてその1
select_type Select の種類
table 参照するテーブル
possible_keys 使用可能なインデックスリスト
key MySQL が実際に使用を決定したインデックス
重要
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE test_tbl ref col_index_1,col_index_2 col_index_1 4 const 1 Using where
EXPLAINで出力される各項目についてその2
key_len インデックスのキー長
ref 検索条件で、keyと比較されているカラムまたは定数
rows 検索される推定レコード数 同じ結果となる SQL ならここが少ないほど良い
重要
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE test_tbl ref col_index_1,col_index_2 col_index_1 4 const 1 Using where
EXPLAINで出力される各項目についてその3
type結合型
const 一致するレコードが最大 1 つ UNIQUE または PRIMARY KEY のインデックスの等価検索
eq_ref 1:1のJOIN UNIQUE または PRIMARY KEY のインデックスを使用
ref 1:nのJOIN UNIQUE または PRIMARY KEY 以外のインデックスを使用
ref_or_null NULLを使用したレコードの補足検索も追加実行される
重要
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE test_tbl ref col_index_1,col_index_2 col_index_1 4 const 1 Using where
EXPLAINで出力される各項目についてその4
Index_merge インデックスマージが使用される
unique_subquery サブクエリで UNIQUE または PRIMARY KEY のインデックスを使用
index_subquery サブクエリで UNIQUE または PRIMARY KEY 以外 のインデックスを使用
range インデックスを使用した範囲検索
index フルインデックススキャン インデックスに対するALLのため遅い
ALL フルテーブルスキャン インデックスの追加などで回避可能
これが出たら注意
EXPLAINで出力される各項目についてその5
Extra どのようにクエリが解決されるかに関する追加情報 数が多いので出たら注意なもののみ記載
Using filesort ORDER BY にインデックスを使用できない
Using temporary クエリの解決にテンポラリテーブルの作成が必要 DISTINCT の使用時や ORDER BY にインデックスを使用できない場合、ORDER BYとGROUP BY式が異なる場合など
これが出たら注意
重要
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE test_tbl ref col_index_1,col_index_2 col_index_1 4 const 1 Using where
EXPLAIN出力結果からできるSQLチューニング
SQLをチューニングするには type, key, rows, extra が重要
type index, ALL の場合はチューニングできないか検討する
key 想定通りのインデックスが使用されているか確認する
rows より件数を絞り込むことは可能か検討する
Extra using filesort, using temporary の場合はチューニングできないか検討する
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE test_tbl ref col_index_1,col_index_2 col_index_1 4 const 1 Using where
参考資料
MySQL 5.1 リファレンスマニュアル :: 6 最適化 :: 6.2 SELECTステートメントおよびその他のクエリの最適化http://dev.mysql.com/doc/refman/5.1/ja/query-speed.html
MySQL Practice Wikihttp://www.mysqlpracticewiki.com/
その他
データ作成に使用したマシンのスペック
MySQL 5.1.56
CPU 2GHz Intel Core Duo
RAM 2GB