MySQL INDEX+EXPLAIN入門

29
MySQL INDEX+EXPLAIN入門 株式会社インフィニットループ ota 作成:2011/3/11 最終更新:2011/4/1

Transcript of MySQL INDEX+EXPLAIN入門

Page 1: MySQL INDEX+EXPLAIN入門

MySQLINDEX+EXPLAIN入門

株式会社インフィニットループ

ota

作成:2011/3/11 最終更新:2011/4/1

Page 2: MySQL INDEX+EXPLAIN入門

このスライドの内容

MySQL5.1 InnoDB を前提とした INDEX と EXPLAIN の初級編

Page 3: MySQL INDEX+EXPLAIN入門

目次

INDEX を使おう

INDEX とは何か

INDEX を使用する時に気をつけること

INDEX を作成する時に気をつけること

EXPLAIN を使おう

EXPLAIN とは何か

EXPLAIN で出力される各項目について

EXPLAIN 出力結果からできる SQL チューニング

Page 4: MySQL INDEX+EXPLAIN入門

INDEXとは何か

テーブルにおける本の索引のようなもの※索引:本の中の語句や事項などを一定の順序(あいうえお順等)に並べ、その語句や事項のあるページを示した表

索引を使わずに目的のページを1ページ目から順番に探す(インデックスを使用しない SELECT)

→ 遅い

索引を使って目的のページを探す (インデックスを使用した SELECT)

→ 早い

※ただし単純な検索の場合、1,000レコード以下ならインデックスがない方が速いことも

Page 5: MySQL INDEX+EXPLAIN入門

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 にかかる時間が件数に比例して増加する

無し 有り

Page 6: MySQL INDEX+EXPLAIN入門

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

Page 7: MySQL INDEX+EXPLAIN入門

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

Page 8: MySQL INDEX+EXPLAIN入門

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

Page 9: MySQL INDEX+EXPLAIN入門

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

Page 10: MySQL INDEX+EXPLAIN入門

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

Page 11: MySQL INDEX+EXPLAIN入門

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

拡大

Page 12: MySQL INDEX+EXPLAIN入門

以下の場合 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

Page 13: MySQL INDEX+EXPLAIN入門

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

Page 14: MySQL INDEX+EXPLAIN入門

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

Page 15: MySQL INDEX+EXPLAIN入門

HAVING句 はインデックスが使用されない

使用して欲しいインデックスが使用されない場合は FORCE INDEX を使ってインデックスを指定することができる

想定したインデックスを使用する SQL になっているかを EXPLAIN で確認する

※レコード数やデータの内容により使用されるインデックスが変わる可能性があるので、実際に近いデータを使用することが重要

INDEXを使用する時に気をつけることその他

Page 16: MySQL INDEX+EXPLAIN入門

INDEXを作成する時に気をつけることその1

基本的に選択性の高い項目がインデックスだと効果が高い

選択性が高い → その項目で絞り込んだ結果件数が少ない

選択性が低い → その項目で絞り込んだ結果件数が多い※性別、ON/OFFフラグとして使用する項目など※ほとんどフラグが立っていない項目の、フラグが立っているものを抽出する場合などは 選択性が低くても結果件数が少なくなるためインデックスにすると効果が高い

複合インデックスは先頭から順に部分インデックスとしても使用できるので、単独で使われることもあるカラムはインデックスの最初の列に指定する

複合インデックスは選択性の高いものを先頭にする

Page 17: MySQL INDEX+EXPLAIN入門

INDEXを作成する時に気をつけることその2

インデックスサイズが増えることによる影響

検索速度が低下

INSERT、UPDATE、DELETE時インデックスを作り直す速度が低下

インデックス情報を格納するためDB容量が増加

メモリに収まるサイズを超えると、ディスクからの読み込みが発生して速度が大幅低下

Page 18: MySQL INDEX+EXPLAIN入門

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

Page 19: MySQL INDEX+EXPLAIN入門

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回毎の平均値

インデックスが多い方がより時間がかかる

複数の単体インデックスよりも同項目の複合インデックスの方が速い

Page 20: MySQL INDEX+EXPLAIN入門

INDEXを作成する時に気をつけることその3

インデックスサイズを減らすには

不要なインデックスを作成しない

インデックスのキー長を短くする 小さいサイズのデータ型を使用する、長い文字列などをインデックスにしない

データ自体を減らす

Page 21: MySQL INDEX+EXPLAIN入門

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

Page 22: MySQL INDEX+EXPLAIN入門

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

Page 23: MySQL INDEX+EXPLAIN入門

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

Page 24: MySQL INDEX+EXPLAIN入門

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

Page 25: MySQL INDEX+EXPLAIN入門

EXPLAINで出力される各項目についてその4

Index_merge インデックスマージが使用される

unique_subquery サブクエリで UNIQUE または PRIMARY KEY のインデックスを使用

index_subquery サブクエリで UNIQUE または PRIMARY KEY 以外 のインデックスを使用

range インデックスを使用した範囲検索

index フルインデックススキャン インデックスに対するALLのため遅い

ALL フルテーブルスキャン インデックスの追加などで回避可能

これが出たら注意

Page 26: MySQL INDEX+EXPLAIN入門

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

Page 27: MySQL INDEX+EXPLAIN入門

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

Page 28: MySQL INDEX+EXPLAIN入門

参考資料

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/

Page 29: MySQL INDEX+EXPLAIN入門

その他

データ作成に使用したマシンのスペック

MySQL 5.1.56

CPU 2GHz Intel Core Duo

RAM 2GB