EXPLAIN tbl_name
または
EXPLAIN [EXTENDED | PARTITIONS] SELECT select_options
EXPLAIN
ステートメントはDESCRIBE
のシノニムとして使用するか、MySQLがどのようにSELECT
ステートメントを実行するかの情報が得られます。
EXPLAIN
はtbl_name
DESCRIBE
またはtbl_name
SHOW COLUMNS FROM
のシノニムです。
tbl_name
キーワード EXPLAIN
を
SELECT
ステートメントの前に置いた場合、MySQL
によってテーブルの結合状況と順序に関する情報が提供され、テーブルの
SELECT
の処理方法が説明されます。
EXPLAIN PARTITIONS
はMySQL
5.1.5から提供されています。区割りされたテーブルのクエリを調べるときに便利です。詳細については、
項15.3.4. 「パーティション情報の取得」
をご参照ください。
このセクションでは、クエリ実行情報を得るためのEXPLAIN
の2つめの使用方法を記述します。DESCRIBE
とSHOW
COLUMNS
ステートメントの詳細については、項12.3.1. 「DESCRIBE
構文」と項12.5.4.4. 「SHOW COLUMNS
構文」を参照してください。
EXPLAIN
を利用すると、より速くレコードを検索する
SELECT
を得るために、どの時テーブルにインデックスを追加しなければならないかを確認できます。
また、EXPLAIN
を使用して、オプティマイザがテーブルを最適な順序で結合しているかどうかも確認することができます。オプティマイザが特定の順番で結合を行うように強制するにはただSELECT
でステートメントをはじめるのではく、SELECT
ステートメントに
SELECT STRAIGHT_JOIN
節を追加します。
最適化方法の選択に影響を及ぼすキーの、カーディナリティなどのテーブル統計を更新するために、ANALYZE
TABLE
を定期的に実行する必要があります。
項12.5.2.1. 「ANALYZE TABLE
構文」を参照してください。
EXPLAIN
はSELECT
ステートメントで使用される各テーブルに関する情報を返します。テーブルは、読み取られた順序に従って一覧表示されます。MySQL
は、単一スイープ多結合メソッドを使用してすべての結合を解決します。これは、MySQL
が最初のテーブルからレコードを読み取ってから、第
2 のテーブル、第 3
のテーブルといった順序で、一致するレコードの検索を行うことを意味します。すべてのテーブルの処理が終わると、選択したカラムと、さらに一致レコードがあるテーブルが検索されるまでのテーブル一覧のバックトラックが出力されます。次のレコードはこのテーブルから読み取られ、処理が次のテーブルから続行されます。
EXTENDED
キーワードが使用された時、EXPLAIN
はSHOW
WARNINGS
ステートメントをEXPLAIN
ステートメントの後で発行することで閲覧できる余分な情報を表示する。この情報は、SELECT
ステートメント内でオプティマイザがどのようにテーブル名とカラム名を認証するか、SELECT
が再書き込みと最適化ルールの適用後どのように表示されるか、そして最適化プロセスの他の注意点なども表示します。EXPLAIN
EXTENDED
はMySQL
5.1.12以降、filtered
カラムも表示します。
注:EXTENDED
とPARTITIONS
キーワードを、同じEXPLAIN
ステートメントで使用することはできません。
EXPLAIN
の各出力行は1つのテーブルの情報を提供し、各行は以下のカラムを含んでいます。
id
SELECT
識別子。クエリ内におけるこの
SELECT
の順序番号。
select_type
SELECT
節の種類、次のいずれかが示される。
SIMPLE |
単純なSELECT
(UNION やサブクエリを使用しない)。 |
PRIMARY |
最外部のSELECT 。 |
UNION |
内の第2およびそれ以降のSELECT ステートメント。 |
DEPENDENT UNION |
UNION 内の第2およびそれ以降のSELECT ステートメント内のUNION 、外側のサブクエリに依存する。 |
UNION RESULT |
UNION の結果。 |
SUBQUERY |
サブクエリ内の第一SELECT 。 |
DEPENDENT SUBQUERY |
第1SELECT 、外側のサブクエリに依存する。 |
DERIVED |
派生テーブルSELECT
(FROM 節内のサブクエリ) |
UNCACHEABLE SUBQUERY |
結果がキャッシュされず、外側のクエリの各行ごとに再評価されるサブクエリ。 |
DEPENDENT
は主に、相互に関係するサブクエリの使用を表します。項12.2.8.7. 「相関サブクエリ」を参照してください。
「依存型サブクエリ」の評価はUNCACHEABLE
SUBQUERY
評価とは異なります。「DEPENDENT
SUBQUERY」に関しては、外側コンテキストの変数の値が異なるたびに、一回のみサブクエリの再評価が行われます。UNCACHEABLE
SUBQUERY
に関しては、サブクエリは外側コンテキストの各行ごとに再評価されます。サブクエリのキャッシュアビリティは項4.13.1. 「クエリ キャッシュの動作」で記述される制限によります。例えば、ユーザ変数に参照することでサブクエリがキャッシュできなくなります。
テーブル
結果を得るために参照するテーブル。
type
結合型。各結合型を最適なものから順に紹介する。
1 レコードのみで構成されるテーブル(=
システムテーブル)。これは、const
結合型の特殊なケースである。
テーブルに、一致するレコードが最大で 1
つあり、クエリの開始時に読み取られる。レコードが
1
つしかないため、このレコードのカラムの値はオプティマイザによって定数と見なされる。const
テーブルは、1
回しか読み取られないため、非常に高速である。
const
はPRIMARY
KEY
/UNIQUE
キーを定数と比較する場合に使用される。
.下記のクエリでは、tbl_name
はconst
テーブルとして使用できる。
SELECT * FROMtbl_name
WHEREprimary_key
=1; SELECT * FROMtbl_name
WHEREprimary_key_part1
=1 ANDprimary_key_part2
=2;
eq_ref
前のテーブルのレコードの組み合わせのそれぞれに対して、このテーブルから
1
レコードずつ読み取られる。これは、system
とconst
型以外で最適な結合型である。
結合でインデックスのすべての部分が使用され、このインデックスが
UNIQUE
または PRIMARY
KEY
である場合に使用される。
=
演算子と比較されるインデックスの張られたカラムには、eq_ref
を使用できる。
較対象のアイテムは定数でも、このテーブル以前に読み取られたテーブルのカラムを使用する式でもかまわない。
下記の例では、ref_table
で
eq_ref
が使用される。
SELECT * FROMref_table
,other_table
WHEREref_table
.key_column
=other_table
.column
; SELECT * FROMref_table
,other_table
WHEREref_table
.key_column_part1
=other_table
.column
ANDref_table
.key_column_part2
=1;
ref
前のテーブルのレコードの組み合わせのそれぞれに対して、インデックス値にマッチするすべてのレコードがこのテーブルから読み取られる。ref
は、インデックスの左端の先頭部分のみが結合で使用される場合、またはインデックスが
UNIQUE
や PRIMARY
KEY
ではない場合(すなわち、この結合において、インデックス値から1つのレコードをSELECTできない場合)に使用される。この結合型は、使用されるインデックスと一致するレコードが数レコードしかない場合に適している。
=
あるいは<=>
演算子と比較されるインデックスの張られたカラムには、ref
を使用できる。
下記の例では、MySQLはref_table
で
ref
が使用される。
SELECT * FROMref_table
WHEREkey_column
=expr
; SELECT * FROMref_table
,other_table
WHEREref_table
.key_column
=other_table
.column
; SELECT * FROMref_table
,other_table
WHEREref_table
.key_column_part1
=other_table
.column
ANDref_table
.key_column_part2
=1;
ref_or_null
ref
と同様だが、NULL
を使用したレコードの補足検索も追加で実行される。
この結合型の最適化は主としてサブクエリを解決する場合に使用される。
下記の例では、MySQLはref_table
で
ref_or_null
が使用される。
SELECT * FROMref_table
WHEREkey_column
=expr
ORkey_column
IS NULL;
index_merge
この結合型はインデックス併合最適化が使用されたことを示しています。この場合、出力行のkey
カラムは使用されたインデックスのリストが含まれ、key_len
には使用されたインデックスの最長キー部分が含まれます。詳細は
項6.2.6. 「インデックス結合最適化」
をご覧ください。
unique_subquery
この型は、下記のフォームでIN
サブクエリの代わりに、ref
を使用します。
value
IN (SELECTprimary_key
FROMsingle_table
WHEREsome_expr
)
unique_subquery
は、効率化のためサブクエリの代わりをつとめるインデックスルックアップ関数です。
index_subquery
この結合型はunique_subquery
に似ています。IN
サブクエリの代わりに使用されますが、下記のサブクエリのフォームでユニークではないインデックスで使用できます。
value
IN (SELECTkey_column
FROMsingle_table
WHEREsome_expr
)
range
インデックスを使用して、一定の範囲にあるレコードのみが取り出される。key
カラムに使用されるインデックスが示される。key_len
_には使用される最長のインデックス部分が記載される。
この型ではref
カラムがNULL
になる。
range
は、インデックスを張っているカラムが
=
、<>
、>
、>=
、<
、<=
、IS
NULL
、<=>
、BETWEEN
、およびIN
を使用して定数と比較される場合に使用される。
SELECT * FROMtbl_name
WHEREkey_column
= 10; SELECT * FROMtbl_name
WHEREkey_column
BETWEEN 10 and 20; SELECT * FROMtbl_name
WHEREkey_column
IN (10,20,30); SELECT * FROMtbl_name
WHEREkey_part1
= 10 ANDkey_part2
IN (10,20,30);
index
これは、インデックスツリーのみがスキャンされる点を除いて
ALL
と同じである。一般にインデックスファイルはデータファイルより小さいため、通常は
ALL
より高速である。
MySQL は、クエリで 1 インデックスの構成部分であるカラムのみが使用される場合にのみ使用できます。
ALL
前のテーブルのレコードの組み合わせのそれぞれに対して、フルテーブルスキャンが実行される。一般に、テーブルが
const
の指定がない第 1
テーブルの場合には適さず、その他の場合はすべて非常に不適である。
通常は、さらにインデックスを追加することで
ALL
を回避し、定数値または以前のテーブルのカラム値を基準にレコードを取り出すようにすることができる。
possible_keys
possible_keys
カラムは、このテーブル内のレコードの検索に
MySQL
で使用可能なインデックスを示す。このカラムはEXPLAIN
からの出力により表示されたテーブルの順序にはまったく依存しないことに注意する。すなわち、possible_keys
のキーの一部は、生成されたテーブルの順序では事実上使用できないことになる。
このカラムが
NULL
の場合は、対応するインデックスがない。tこの場合は、WHERE
節でインデックス作成に適するカラムを
1
つ以上参照しているかどうかを調べることでクエリのパフォーマンスを改善できる。
参照している場合は適切なインデックスを作成し、再度
EXPLAIN
を使用してクエリをチェックする。
項12.1.2. 「ALTER TABLE
構文」を参照してください。
テーブルにあるインデックスを調べるには
SHOW INDEX FROM
を使用する。
tbl_name
key
key
カラムは、MySQL
が実際に使用を決定したキー(インデックス)を示す。
MySQL
が行をルックアップするためpossible_keys
インデックスを使用した場合、キー値としてそのインデックスがリストされる。
key
はpossible_keys
値に存在しないインデックスを指名する可能性もあります。これはpossible_keys
インデックスのうちどれも行をルックアップするのに適していない場合におこりますが、クエリに選択された全てのカラムは他のインデックスのカラムになります。つまり、指名されたインデックスが選択されたカラムをカバーします。どの行を取得するか判別するのに使用されていなくとも、データ行スキャンよりもインデックススキャンの方が効率的です。
InnoDB
では、クエリがプライマリキーを選択していてもセカンダリインデックスが選択されたカラムをカバーするかもしれません。これはクエリがプライマリキーを選択した場合もありえるのは、InnoDB
が各セカンダリインデックスと共にプライマリキー値も保存するからです。MySQLがクエリを効率的に実行するインデックスを見つけられなかった場合、このkey
は
NULL
になる。
MySQLで
possible_keys
カラムに記載されたキーが使用されるように強制するには、クエリでFORCE
INDEX
、USE
INDEX
、またはIGNORE
INDEX
を使用する。
項12.2.7. 「SELECT
構文」を参照してください。
MyISAM
テーブルには、ANALYZE
TABLE
を実行することでオプティマイザでより適したインデックスを選択する際役立つ。MyISAM
テーブルに関しても、myisamchk
--analyzeは同じことをします。項12.5.2.1. 「ANALYZE TABLE
構文」、項4.9.4. 「テーブル保守とクラッシュ リカバリ」
を参照して下さい。
key_len
key_len
カラムは、MySQL
が実際に使用を決定したキーの長さを示す。
key
が
NULL
の場合、この長さは
NULL
になる。
key_len
の値によって、複合キーで
MySQL
が実際に使用するパート数が示されることに注意する。
ref
ref
カラムは、テーブルからレコードを選択する際に
key
とともに使用されるカラムまたは定数を示す。
rows
rows
カラムは、クエリの実行に際して調べる必要があると
MySQL
によって判定されたレコードの数を示す。
filtered
filtered
カラムはテーブルの状態によってフィルターされるテーブル行のパーセンテージ(予想)を表示します。つまり、rows
は検査された行の予想数を表示し、rows
× filtered
/
100
は前のテーブルと結合する行の数を表示します。EXPLAIN
EXTENDED
を使用すると、このカラムが表示されます。(MySQL
5.1.12の新しい機能です。)
Extra:
このカラムには、MySQL
でどのようにクエリが解決されるかに関する追加情報が記載される。下記のリストはこのカラムで表示される可能性のある値を説明する。クエリの速度をできる限り上げたい場合は、Using
filesort
とUsing
temporary
のExtra
値に注目してください。
Distinct
マッチした最初のレコードが検索されると、MySQL は現在のレコードの組み合わせによるその後のレコード検索を続行しないことを示す。
const tablesを読んだ後 Impossible
WHERE発見
MySQL は全てのconst
(あと、system
)
テーブルを読んだ後、WHERE
節が常に偽となります。
No tables
クエリにはFROM
節がないか、FROM
DUAL
節があります。
Not exists
MySQL でクエリに対する LEFT
JOIN
最適化が実行でき、LEFT
JOIN
に一致するレコードが 1
つ検索されると、前のレコードの組み合わせによるその後のテーブルのレコードについては調べないことを示す。
このように最適化できるクエリの例を以下に示します。
SELECT * FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.id IS NULL;
t2.id
が NOT
NULL
で定義されているとする。この場合、MySQL
で
t1
がスキャンされ、t1.id
で
t2
内のレコードのルックアップが行われる。MySQL
によって
t2
内のマッチするレコードが検索されると、t2.id
はNULL
ではないと認識され、t2
内の同じ
id
を持つ残りのレコードのスキャンは行われない。言い換えると、t2
にあるマッチするレコードの数に関わらず、MySQL
で実行が必要なことは
t1
のレコードのそれぞれに対して、t2
のルックアップを
1 回実行することだけである。
range checked for each record (index map:
N
)
MySQL
で使用に適した実際のインデックスを検索できなかったことを示す。代替として、先行テーブルのレコードの組み合わせのそれぞれに対して、使用するインデックス(存在する場合)range
またはindex_merge
のチェックが実行され、このインデックスがテーブルからのレコードの取り出しに使用される。非常に高速ではないが、インデックスなしの結合と比較すると高速である。
適用基準は項6.2.5. 「Range 最適化」と項6.2.6. 「インデックス結合最適化」で説明されています。ただし、これは前テーブルの全てのカラム値が知られており、定数であるという前提においてです。
Select tables optimized away
クエリはMyISAM
用に、インデックスで解決された集約ファンクション(MIN()
、MAX()
)そしてCOUNT(*)
があり、GROUP
BY
節は含みませんでした。オプティマイザは1つの行のみが返されるべきと判断しました。
Using filesort
レコードをソートして取り出す方法を決定するには、MySQL
はパスを余分に実行しなくてはならないことを示す。
join type
に従ってすべてのレコードをスキャンし、WHERE
条件に一致する全てのレコードに、ソートキー
+
行ポインタを格納して、ソートは実行される。その後キーがソートされる。
最後に、ソートされた順にレコードが取り出される。項6.2.12. 「ORDER BY
最適化」を参照してください。
Using index
インデックスツリーの情報のみを使用してカラム情報がテーブルから取り出され、実際の行を読み取るその後の検索を実行する必要がないことを示す。MySQL は、クエリで 1 インデックスの構成部分であるカラムのみが使用される場合にのみ使用できます。
Using temporary
クエリの解決に MySQL
で結果を保持するテンポラリテーブルの作成が必要であることを示す。これは一般に、GROUP
BY
を実行したカラムセットと異なるカラムセットに対して
ORDER
BY
を実行した場合に発生する。
Using where
次のテーブルとの一致が調べられるレコードまたはクライアントに送信されるレコードの限定に
WHERE
節が使用されることを示す。
この情報がなく、Extra
の値がUsing
where
ではなく、テーブルの型が
ALL
または
index
である場合はクエリが正常に実行されないことがある(テーブルのすべてのレコードの取得や検査を意図していない場合)。
Using
sort_union(...)
、Using
union(...)
、Using
intersect(...)
これらはindex_merge
結合型でインデックススキャンがどのように併合されるかを示しています。詳細は
項6.2.6. 「インデックス結合最適化」 を参照。
Using index for group-by
Using
index
を使用してテーブルをアクセスする方法に似て、Using
index for
group-by
はMySQLが余分なディスクアクセスを実際のテーブルに行うことなく、GROUP
BY
またはDISTINCT
クエリのカラムを全て取得することができるインデックスを見つけたことを意味します。加えて、インデックスは各グループにとって最も効率的に使われるので、数種類のインデックスしか読まれません。詳細については、項6.2.13. 「GROUP BY
最適化」をご参照ください。
Using where with pushed condition
このアイテムはNDB
Cluster
テーブルにのみ適用されます。それはMySQL
クラスタがcondition
pushdownを使用して行う、インデックスのないカラムと定数を直接比較(=
)の効率化を図ることを意味します。その場合、状態はクラスターのデータノードに「押し戻され」ており、全てのパーティションで同時に評価されます。これはマッチしない行をネットワーク上で送る必要を無くし、コンディションプッシュダウンが使える状態にあり、使用しないケースでそのようなクエリの速度を5乗から10乗に増やす。
以下のように定義されたクラスタテーブルがあるとします。
CREATE TABLE t1 ( a INT, b INT, KEY(a) ) ENGINE=NDBCLUSTER;
この場合、コンディションプッシュダウンは下記のようなクエリで使用できます。
SELECT a,b FROM t1 WHERE b = 10;
これはEXPLAIN
SELECT
の出力で見られます。例えば
mysql> EXPLAIN SELECT a,b FROM t1 WHERE b = 10\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t1
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 10
Extra: Using where with pushed condition
コンディションプッシュダウンは下記の2つのクエリと一緒には使用できません。
SELECT a,b FROM t1 WHERE a = 10; SELECT a,b FROM t1 WHERE b + 1 = 10;
この二つのクエリのうち最初のものに関しては、インデックスがa
カラムに存在するため、コンディションプッシュダウンは適用できません。2番目のクエリの場合、インデックスのないカラムb
に関する比較は直接的でないため、コンディションプッシュダウンが適用できません。(ただし、b
+ 1 = 10
をWHERE
節内でb =
9
に減らす場合は適用されます。)
ただし、>
または<
演算子を使用している定数とインデックスカラムが比較された場合、コンディションプッシュダウンが使用される場合もあります。
mysql> EXPLAIN SELECT a,b FROM t1 WHERE a<2\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t1
type: range
possible_keys: a
key: a
key_len: 5
ref: NULL
rows: 2
Extra: Using where with pushed condition
コンディションプッシュダウンに関して、以下のことに留意してください。
コンディションプッシュダウンはMySQLクラスタにのみ関連しており、他の保存エンジンを使用するテーブルに対してクエリを実行するときは起こりえません。
コンディションプッシュダウン機能はデフォルトでは使用されません。起動するには、mysqld
を--engine-condition-pushdown
オプションで使用するか、以下のステートメントを実行してください。
SET engine_condition_pushdown=On;
注:コンディションプッシュダウンはBLOB
やTEXT
タイプのどのカラムに対してもサポートされていません。
EXPLAIN
出力の
rows
カラムのすべての値を掛け算することで、結合がどの程度適しているかを示す指針を取得できます。Thisこれは、クエリの実行時に
MySQL
で調べる必要があるレコード数の概要を示します。この数値は、max_join_size
変数でクエリを制限する際にも使用される他、どのマルチテーブルSELECT
ステートメントを実行するか、あるいはアボートするかを判別します。項6.5.2. 「サーバパラメータのチューニング」を参照してください。
下記の例は、EXPLAIN
によって得られた情報を使用して、マルチテーブルjoinを累進的に最適化する方法を示しています。
ここでは、EXPLAIN
を使用して、SELECT
ステートメントを調べるとします。
EXPLAIN SELECT tt.TicketNumber, tt.TimeIn, tt.ProjectReference, tt.EstimatedShipDate, tt.ActualShipDate, tt.ClientID, tt.ServiceCodes, tt.RepetitiveID, tt.CurrentProcess, tt.CurrentDPPerson, tt.RecordVolume, tt.DPPrinted, et.COUNTRY, et_1.COUNTRY, do.CUSTNAME FROM tt, et, et AS et_1, do WHERE tt.SubmitTime IS NULL AND tt.ActualPC = et.EMPLOYID AND tt.AssignedPC = et_1.EMPLOYID AND tt.ClientID = do.CUSTNMBR;
この例では以下のように想定しています。
比較対象のカラムは以下のように宣言されます。
テーブル | カラム | データ型 |
tt |
ActualPC |
CHAR(10) |
tt |
AssignedPC |
CHAR(10) |
tt |
ClientID |
CHAR(10) |
et |
EMPLOYID |
CHAR(15) |
do |
CUSTNMBR |
CHAR(15) |
テーブルには以下のインデックスがあります。
テーブル | インデックス |
tt |
ActualPC |
tt |
AssignedPC |
tt |
ClientID |
et |
EMPLOYID (プライマリキー) |
do |
CUSTNMBR (プライマリキー) |
tt.ActualPC
値の分布が均一ではない。
当初、最適化の実行前は、EXPLAIN
ステートメントで次の情報が生成されました。
table type possible_keys key key_len ref rows Extra et ALL PRIMARY NULL NULL NULL 74 do ALL PRIMARY NULL NULL NULL 2135 et_1 ALL PRIMARY NULL NULL NULL 74 tt ALL AssignedPC, NULL NULL NULL 3872 ClientID, ActualPC range checked for each record (key map: 35)
各テーブルで type
が
ALL
であるため、この出力は MySQL
がすべてのテーブルのデカルト積を生成すると示しています。各テーブルのレコードの数の積の分量を調べる必要があるため、これは非常に時間がかかります。この例の場合は、レコードの数が
74 ×2135 ×74 ×3872 = 45,268,558,720
になります。テーブルがこれより大きい場合は、さらに時間がかかると考えられます。
ここでの問題の 1 つは、宣言の方法が異なると
MySQL
でカラムのインデックスを効率的に使用できないことにあります。この例では、VARCHAR
と
CHAR
が異なる長さで宣言されていなければ同じになります。tt.ActualPC
が
CHAR(10)
として、et.EMPLOYID
が
CHAR(15)
として宣言されているため、長さの不一致が発生します。
カラムの長さの不一致を修正するため、ALTER
TABLE
を使用して ActualPC
を 10
文字から 15 文字にします。
mysql> ALTER TABLE tt MODIFY ActualPC VARCHAR(15);
これで tt.ActualPC
と
et.EMPLOYID
はいずれも
VARCHAR(15)
になりました。
ここでまた
EXPLAIN
を実行してみると、以下の結果が得られました。
table type possible_keys key key_len ref rows Extra tt ALL AssignedPC, NULL NULL NULL 3872 Using ClientID, where ActualPC do ALL PRIMARY NULL NULL NULL 2135 range checked for each record (key map: 1) et_1 ALL PRIMARY NULL NULL NULL 74 range checked for each record (key map: 1) et eq_ref PRIMARY PRIMARY 15 tt.ActualPC 1
これも完全ではありませんが、かなり改善されています(rows
値の積が
74
の係数分だけ減少)。このバージョンの場合実行に数秒かかります。
第 2 の変更を加えると、tt.AssignedPC =
et_1.EMPLOYID
と tt.ClientID =
do.CUSTNMBR
の比較でのカラム長の不一致を解消できます。
mysql>ALTER TABLE tt MODIFY AssignedPC VARCHAR(15),
->MODIFY ClientID VARCHAR(15);
ここでは、EXPLAIN
から以下の出力が生成されます。
table type possible_keys key key_len ref rows Extra et ALL PRIMARY NULL NULL NULL 74 tt ref AssignedPC, ActualPC 15 et.EMPLOYID 52 Using ClientID, where ActualPC et_1 eq_ref PRIMARY PRIMARY 15 tt.AssignedPC 1 do eq_ref PRIMARY PRIMARY 15 tt.ClientID 1
これでほとんど改善されています。
残りの問題は、MySQL ではデフォルトで
tt.ActualPC
カラムの値の分布が均一であると想定されますが、tt
テーブルはこれにあてはまらないことです。これは容易に
MySQL に示すことができます。
mysql> ANALYZE TABLE tt;
この追加インデックス情報で、結合が完全になり、EXPLAIN
で以下の結果が生成されます。
table type possible_keys key key_len ref rows Extra tt ALL AssignedPC NULL NULL NULL 3872 Using ClientID, where ActualPC et eq_ref PRIMARY PRIMARY 15 tt.ActualPC 1 et_1 eq_ref PRIMARY PRIMARY 15 tt.AssignedPC 1 do eq_ref PRIMARY PRIMARY 15 tt.ClientID 1
EXPLAIN
の出力の
rows
カラムは、MySQL
結合オプティマイザの学習による推測であることに注意してください。クエリを最適化するには、この数値が実際に近いものであるかどうかを確認するためにrows
のプロダクトとクエリが実際に返す行の数をを比較する必要があります。実際とかけ離れている場合は、SELECT
ステートメントで
STRAIGHT_JOIN
を使用し、FROM
節でテーブルの順序を変えて一覧表示してみるとパフォーマンスを改善できます。
MySQL Enterprise. MySQL ネットワーク監視とアドバイスサービス加入者は定期的にプロから最適化のアドバイスを提供されます。追加情報については http://www-jp.mysql.com/products/enterprise/advisors.htmlを参照してください。