EXPLAIN tbl_name
または
EXPLAIN [EXTENDED | PARTITIONS] SELECT select_options
EXPLAINステートメントはDESCRIBEのシノニムとして使用するか、MySQLがどのようにSELECT
ステートメントを実行するかの情報が得られます。
EXPLAIN
はtbl_nameDESCRIBE
またはtbl_nameSHOW 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_nameWHEREprimary_key=1; SELECT * FROMtbl_nameWHEREprimary_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_tableWHEREref_table.key_column=other_table.column; SELECT * FROMref_table,other_tableWHEREref_table.key_column_part1=other_table.columnANDref_table.key_column_part2=1;
ref
前のテーブルのレコードの組み合わせのそれぞれに対して、インデックス値にマッチするすべてのレコードがこのテーブルから読み取られる。refは、インデックスの左端の先頭部分のみが結合で使用される場合、またはインデックスが
UNIQUEや PRIMARY
KEYではない場合(すなわち、この結合において、インデックス値から1つのレコードをSELECTできない場合)に使用される。この結合型は、使用されるインデックスと一致するレコードが数レコードしかない場合に適している。
=あるいは<=>演算子と比較されるインデックスの張られたカラムには、ref
を使用できる。
下記の例では、MySQLはref_tableで
refが使用される。
SELECT * FROMref_tableWHEREkey_column=expr; SELECT * FROMref_table,other_tableWHEREref_table.key_column=other_table.column; SELECT * FROMref_table,other_tableWHEREref_table.key_column_part1=other_table.columnANDref_table.key_column_part2=1;
ref_or_null
refと同様だが、NULLを使用したレコードの補足検索も追加で実行される。
この結合型の最適化は主としてサブクエリを解決する場合に使用される。
下記の例では、MySQLはref_tableで
ref_or_nullが使用される。
SELECT * FROMref_tableWHEREkey_column=exprORkey_columnIS NULL;
index_merge
この結合型はインデックス併合最適化が使用されたことを示しています。この場合、出力行のkeyカラムは使用されたインデックスのリストが含まれ、key_lenには使用されたインデックスの最長キー部分が含まれます。詳細は
項6.2.6. 「インデックス結合最適化」
をご覧ください。
unique_subquery
この型は、下記のフォームでINサブクエリの代わりに、refを使用します。
valueIN (SELECTprimary_keyFROMsingle_tableWHEREsome_expr)
unique_subqueryは、効率化のためサブクエリの代わりをつとめるインデックスルックアップ関数です。
index_subquery
この結合型はunique_subqueryに似ています。INサブクエリの代わりに使用されますが、下記のサブクエリのフォームでユニークではないインデックスで使用できます。
valueIN (SELECTkey_columnFROMsingle_tableWHEREsome_expr)
range
インデックスを使用して、一定の範囲にあるレコードのみが取り出される。keyカラムに使用されるインデックスが示される。key_len_には使用される最長のインデックス部分が記載される。
この型ではrefカラムがNULLになる。
range
は、インデックスを張っているカラムが
=、<>、>、>=、<、<=、IS
NULL、<=>、BETWEEN、およびIN
を使用して定数と比較される場合に使用される。
SELECT * FROMtbl_nameWHEREkey_column= 10; SELECT * FROMtbl_nameWHEREkey_columnBETWEEN 10 and 20; SELECT * FROMtbl_nameWHEREkey_columnIN (10,20,30); SELECT * FROMtbl_nameWHEREkey_part1= 10 ANDkey_part2IN (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を参照してください。
