このページは機械翻訳したものです。
EXPLAIN ステートメントは、MySQL がステートメントを実行する方法に関する情報を提供します。 EXPLAIN は、SELECT, DELETE, INSERT, REPLACE および UPDATE ステートメントで動作します。
EXPLAIN は SELECT ステートメントで使用される各テーブルに関する情報の行を返します。 これは、MySQL がステートメントの処理中にテーブルを読み取る順番で、出力にテーブルを一覧表示します。 これは、MySQL が最初のテーブルから行を読み取り、次に 2 番目のテーブル、3 番目のテーブルなどで一致する行を検索することを意味します。 すべてのテーブルが処理されると、MySQL は選択したカラムを出力し、さらに一致する行があるテーブルが見つかるまで、テーブルリストを逆戻りします。 次の行がテーブルから読み取られ、プロセスは次のテーブルに進みます。
MySQL Workbench には、EXPLAIN 出力を視覚的に表現する Visual Explain 機能があります。 Tutorial: Using Explain to Improve Query Performanceを参照してください。
このセクションでは、EXPLAIN によって生成される出力カラムについて説明します。 あとのセクションで、type と Extra カラムに関する追加情報を提供します。
EXPLAIN からの各出力行は 1 つのテーブルに関する情報を提供します。 各行には、表8.1「EXPLAIN 出力カラム」で要約し、次の表に詳しく説明している値が格納されます。 テーブルの最初のカラムにはカラム名が表示されます。2 番目のカラムには、FORMAT=JSON を使用した場合の出力に表示される同等のプロパティ名が示されます。
表 8.1 EXPLAIN 出力カラム
| カラム | JSON 名 | 意味 |
|---|---|---|
id |
select_id |
SELECT 識別子。 |
select_type |
なし |
SELECT 型 |
table |
table_name |
出力行のテーブル |
partitions |
partitions |
一致するパーティション |
type |
access_type |
結合型 |
possible_keys |
possible_keys |
選択可能なインデックス |
key |
key |
実際に選択されたインデックス |
key_len |
key_length |
選択されたキーの長さ |
ref |
ref |
インデックスと比較されるカラム |
rows |
rows |
調査される行の見積もり |
filtered |
filtered |
テーブル条件によってフィルタ処理される行の割合 |
Extra |
なし | 追加情報 |
NULL である JSON プロパティは、JSON 形式の EXPLAIN 出力には表示されません。
-
SELECT識別子。 これはクエリー内のSELECTの連番です。 行がほかの行の和集合結果を参照する場合に、値はNULLになることがあります。 この場合、tableカラムには、<unionなどの値が表示され、行がM,N>MおよびNのid値のある行の和集合を参照していることが示されます。 -
SELECTの種類で、次の表に示すもののいずれかになります。 JSON 形式のEXPLAINは、SIMPLEまたはPRIMARYでないかぎり、SELECTタイプをquery_blockのプロパティとして公開します。 JSON 名 (該当する場合) もテーブルに示されます。select_type値JSON 名 意味 SIMPLEなし 単純な SELECT(UNIONやサブクエリーを使用しません)PRIMARYなし もっとも外側の SELECTUNIONなし UNION内の 2 つめ以降のSELECTステートメントDEPENDENT UNIONdependent(true)UNION内の 2 つめ以降のSELECTステートメントで、外側のクエリーに依存しますUNION RESULTunion_resultUNIONの結果。SUBQUERYなし サブクエリー内の最初の SELECTDEPENDENT SUBQUERYdependent(true)サブクエリー内の最初の SELECTで、外側のクエリーに依存しますDERIVEDなし 導出テーブル DEPENDENT DERIVEDdependent(true)別のテーブルに依存する導出テーブル MATERIALIZEDmaterialized_from_subquery実体化されたサブクエリー UNCACHEABLE SUBQUERYcacheable(false)結果をキャッシュできず、外側のクエリーの行ごとに再評価される必要があるサブクエリー UNCACHEABLE UNIONcacheable(false)キャッシュ不可能なサブクエリー ( UNCACHEABLE SUBQUERYを参照してください) に属するUNION内の 2 つめ以降の SELECTDEPENDENTは一般に、相関サブクエリーの使用を示します。 セクション13.2.11.7「相関サブクエリー」を参照してください。DEPENDENT SUBQUERYの評価はUNCACHEABLE SUBQUERYの評価とは異なります。DEPENDENT SUBQUERYの場合、その外部コンテキストの変数の異なる値の各セットにつき、一回だけサブクエリーが再評価されます。UNCACHEABLE SUBQUERYの場合、外部コンテキストの行ごとにサブクエリーが再評価されます。EXPLAINでFORMAT=JSONを指定した場合、出力にはselect_typeと直接同等の単一のプロパティはありません。query_blockプロパティは特定のSELECTに対応します。 表示されているほとんどのSELECTサブクエリータイプに相当するプロパティが使用可能で (たとえば、materialized_from_subqueryforMATERIALIZED)、必要に応じて表示されます。SIMPLEまたはPRIMARYに相当する JSON はありません。SELECT以外のステートメントのselect_type値には、影響を受けるテーブルのステートメントタイプが表示されます。 たとえば、select_typeはDELETEステートメント用のDELETEです。 -
出力の行で参照しているテーブルの名前。 これも次のいずれかの値になることがあります。
<union: 行はM,N>MおよびNのid値のある行の和集合を参照しています。<derived: 行はN>Nのid値のある行の派生テーブル結果を参照しています。 派生テーブルは、たとえばFROM句内のサブクエリーの結果などになります。<subquery: 行はN>Nのid値のある行の実体化されたサブクエリーの結果を参照しています。 セクション8.2.2.2「実体化を使用したサブクエリーの最適化」を参照してください。
-
partitions(JSON 名):partitions)クエリーでレコードが照合されるパーティション。 パーティション化されていないテーブルの場合、この値は
NULLです。 セクション24.3.5「パーティションに関する情報を取得する」を参照してください。 -
結合型。 さまざまな型の説明については、「
EXPLAIN結合型」を参照してください。 -
possible_keys(JSON 名):possible_keys)possible_keysカラムは、MySQL がこのテーブルの行を検索するために選択できるインデックスを示します。 このカラムはEXPLAINの出力に表示されたテーブルの順序にまったく依存しません。 つまり、possible_keysのキーの一部は、生成されたテーブルの順序で実際に使用できないことがあります。このカラムが
NULLの場合 (または JSON 形式の出力で未定義の場合)、関連するインデックスはありません。 この場合、WHERE句を調査して、それがインデックス設定に適したカラムを参照しているかどうかをチェックすることで、クエリーのパフォーマンスを向上できることがあります。 その場合は、適切なインデックスを作成し、再度EXPLAINでクエリーをチェックします。 セクション13.1.9「ALTER TABLE ステートメント」を参照してください。テーブルにあるインデックスを確認するには、
SHOW INDEX FROMを使用します。tbl_name -
keyカラムは、MySQL が実際に使用することを決定したキー (インデックス) を示します。 MySQL が行をルックアップするために、いずれかのpossible_keysインデックスを使用することを決定した場合、キー値としてそのインデックスが一覧表示されます。keyは、possible_keys値に存在しないインデックスに名前を付けることができます。 これはpossible_keysインデックスのどれも行のルックアップに適していない場合に発生する可能性がありますが、クエリーによって選択されるすべてのカラムはほかのインデックスのカラムになります。 つまり、指定されたインデックスは選択されたカラムをカバーするため、取得する行を決定するために使用されませんが、インデックススキャンはデータ行スキャンよりも効率的です。InnoDBは各セカンダリインデックスとともに主キー値を保存するため、InnoDBでは、クエリーで主キーも選択している場合でも、セカンダリインデックスで選択されたカラムをカバーしている可能性があります。keyがNULLの場合、MySQL はクエリーをより効率的に実行するために使用するインデックスを見つけられませんでした。MySQL で
possible_keysカラムに示されたインデックスを強制的に使用させるか、無視させるには、クエリーでFORCE INDEX、USE INDEX、またはIGNORE INDEXを使用します。 セクション8.9.4「インデックスヒント」を参照してください。MyISAMテーブルの場合、ANALYZE TABLEを実行すると、オプティマイザがより適切なインデックスを選択するのに役立ちます。MyISAMテーブルの場合、myisamchk --analyze も同様に動作します。 セクション13.7.3.1「ANALYZE TABLE ステートメント」およびセクション7.6「MyISAM テーブルの保守とクラッシュリカバリ」を参照してください。 -
key_len(JSON 名):key_length)key_lenカラムは、MySQL が使用することを決定したキーの長さを示します。key_lenの値を使用すると、MySQL が実際に使用するマルチパーティキーの部分の数を決定できます。keyカラムにNULLと表示されている場合、key_lenカラムにもNULLと表示されます。キーの格納形式のため、キーの長さは、
NULLにできるカラムの長さがNOT NULLカラムの長さより大きくなります。 -
refカラムは、テーブルから行を選択するために、keyカラムに指定されたインデックスに対して比較されるカラムまたは定数を示します。値が
funcの場合、使用される値は、特定の関数の結果です。 どの関数を表示するには、EXPLAINの後のSHOW WARNINGSを使用して、拡張EXPLAIN出力を表示します。 関数は、実際には算術演算子などの演算子である場合があります。 -
rowsカラムは、MySQL がクエリーを実行するために調査する必要があると考える行数を示します。InnoDBテーブルの場合、これは推定値であり、常に正確ではないことがあります。 -
filteredカラムは、テーブル条件でフィルタされるテーブルの行の推定割合を示します。 最大値は 100 で、これは行のフィルタリングが行われなかったことを意味します。 100 から減少する値は、フィルタリングの量が増加していることを示します。rowsには調査された推定行数が表示され、rows×filteredには次のテーブルと結合された行数が表示されます。 たとえば、rowsが 1000 でfilteredが 50.00 (50%) の場合、次のテーブルと結合される行数は 1000×50% = 500 になります。 -
このカラムには、MySQL がクエリーを解決する方法に関する追加情報が含まれます。 さまざまな値の説明については、「
EXPLAINの追加情報」を参照してください。Extraカラムに対応する単一の JSON プロパティはありませんが、このカラムで発生する可能性のある値は JSON プロパティまたはmessageプロパティのテキストとして公開されます。
EXPLAIN 出力の type カラムには、テーブルの結合方法が示されます。 JSON 形式の出力では、これらは access_type プロパティの値として検出されます。 次のリストに、もっとも適切な型からもっとも不適切な型の順番で並べた結合型を示します。
-
テーブルには行が 1 つしかありません (= system テーブル)。 これは、
const結合型の特殊なケースです。 -
テーブルには、一致するレコードが最大で 1 つあり、クエリーの開始時に読み取られます。 行が 1 つしかないため、この行のカラムの値は、オプティマイザの残りによって定数とみなされることがあります。
constテーブルは、1 回しか読み取られないため、非常に高速です。constはPRIMARY KEYまたはUNIQUEインデックスのすべてのパートを定数値と比較する場合に使用されます。 次のクエリーでは、tbl_nameはconstテーブルとして使用できます。SELECT * FROM tbl_name WHERE primary_key=1; SELECT * FROM tbl_name WHERE primary_key_part1=1 AND primary_key_part2=2; -
前のテーブルの行の組み合わせごとに、このテーブルから 1 行ずつ読み取られます。
systemとconst型以外で、これは最適な結合型です。 これは、結合でインデックスのすべてのパートが使用されており、インデックスがPRIMARY KEYまたはUNIQUE NOT NULLインデックスである場合に使用されます。eq_refは、=演算子を使用して比較されるインデックス設定されたカラムに使用できます。 比較値は、定数またはこのテーブルより前に読み取られたテーブルのカラムを使用する式を指定できます。 次の例では、MySQL はeq_ref結合を使用して、ref_tableを処理できます。SELECT * FROM ref_table,other_table WHERE ref_table.key_column=other_table.column; SELECT * FROM ref_table,other_table WHERE ref_table.key_column_part1=other_table.column AND ref_table.key_column_part2=1; -
前のテーブルの行の組み合わせごとに、一致するインデックス値を持つすべての行がこのテーブルから読み取られます。
refは、結合でキーの左端のプリフィクスのみが使用される場合、またはキーがPRIMARY KEYやUNIQUEインデックスではない場合 (つまり、結合で、キー値に基づいて単一の行を選択できない場合) に使用されます。 使用されているキーがほんの数行にしか一致しない場合、これは適切な結合型です。refは、=または<=>演算子を使用して比較されるインデックス設定されたカラムに使用できます。 次の例では、MySQL はref結合を使用して、ref_tableを処理できます。SELECT * FROM ref_table WHERE key_column=expr; SELECT * FROM ref_table,other_table WHERE ref_table.key_column=other_table.column; SELECT * FROM ref_table,other_table WHERE ref_table.key_column_part1=other_table.column AND ref_table.key_column_part2=1; -
結合は
FULLTEXTインデックスを使用して実行されます。 -
この結合型は、
refと似ていますが、MySQL がNULL値を含む行の追加検索を実行することが追加されます。 この結合型の最適化は、ほとんどの場合に、サブクエリーの解決で使用されます。 次の例では、MySQL はref_or_null結合を使用して、ref_tableを処理できます。SELECT * FROM ref_table WHERE key_column=expr OR key_column IS NULL;セクション8.2.1.15「IS NULL の最適化」を参照してください。
-
この結合型はインデックスマージ最適化が使用されたことを示します。 この場合、出力行の
keyカラムには使用されたインデックスのリストが含まれ、key_lenには使用されたインデックスの最長キーパートのリストが含まれます。 詳細については、セクション8.2.1.3「インデックスマージの最適化」を参照してください。 -
このタイプは、次の形式の一部の
INサブクエリーでeq_refに置き換わります:value IN (SELECT primary_key FROM single_table WHERE some_expr)unique_subqueryは、効率化のため、サブクエリーを完全に置き換える単なるインデックスルックアップ関数です。 -
この結合型は
unique_subqueryに似ています。INサブクエリーを置き換えますが、次の形式のサブクエリー内の一意でないインデックスに対して機能します。value IN (SELECT key_column FROM single_table WHERE some_expr) -
行を選択するためのインデックスを使用して、特定の範囲にある行のみが取得されます。 出力行の
keyカラムは、使用されるインデックスを示します。key_lenには使用された最長のインデックスパートが格納されます。 この型のrefカラムはNULLです。rangeは、=,<>,>,>=,<,<=,IS NULL,<=>,BETWEEN,LIKEまたはIN()演算子のいずれかを使用してキーカラムを定数と比較する場合に使用できます:SELECT * FROM tbl_name WHERE key_column = 10; SELECT * FROM tbl_name WHERE key_column BETWEEN 10 and 20; SELECT * FROM tbl_name WHERE key_column IN (10,20,30); SELECT * FROM tbl_name WHERE key_part1 = 10 AND key_part2 IN (10,20,30); -
index結合型は、インデックスツリーがスキャンされることを除いて、ALLと同じです。 これは 2 つの方法で行われます。インデックスがクエリーのカバリングインデックスで、使用すると、テーブルから必要なすべてのデータを満たすことができる場合、インデックスツリーのみがスキャンされます。 この場合、
ExtraカラムにはUsing indexと示されます。 インデックスのサイズは通常テーブルデータより小さいため、インデックスのみのスキャンは通常、ALLより高速です。フルテーブルスキャンは、インデックスからの読み取りを使用して、インデックス順でデータ行をルックアップして実行されます。
ExtraカラムにUses indexが表示されません。
MySQL は、クエリーで単一のインデックスの一部であるカラムのみが使用されている場合に、この結合型を使用できます。
-
フルテーブルスキャンは、前のテーブルの行の組み合わせごとに実行されます。 これは、通常テーブルが
constとマークされていない最初のテーブルである場合には適しておらず、通常ほかのすべてのケースで著しく不適切です。 通常、定数値または以前のテーブルからのカラム値に基づいて、テーブルからの行の取得を可能にするインデックスを追加することで、ALLを回避できます。
EXPLAIN 出力の Extra カラムには、MySQL がクエリーを解決する方法に関する追加情報が含まれます。 次のリストに、このカラムに表示される可能性のある値について説明します。 各セクション目は、JSON 形式の出力に対して、Extra 値を表示するプロパティも示します。 これらの一部には、特定のプロパティがあります。 その他は、message プロパティのテキストとして表示されます。
クエリーをできるだけ高速にする場合は、Using filesort および Using temporary の Extra カラムの値を検索するか、JSON 形式の EXPLAIN 出力で using_filesort および using_temporary_table のプロパティが true に等しいかどうかを調べます。
-
Child of '(JSON:table' pushed join@1messageテキスト)このテーブルは、NDB カーネルにプッシュダウンできる結合内の
tableの子として参照されます。 プッシュダウン結合が有効になっている場合、NDB Cluster でのみ適用されます。 詳細と例については、ndb_join_pushdownサーバーシステム変数の説明を参照してください。 -
const row not found(JSON プロパティ):const_row_not_found)SELECT ... FROMなどのクエリーの場合、テーブルは空でした。tbl_name -
Deleting all rows(JSON プロパティ):message)DELETEに対し、一部のストレージエンジン (MyISAMなど) は簡単で高速にすべての行テーブルを削除するハンドラメソッドをサポートしています。 このExtra値は、エンジンでこの最適化が使用された場合に表示されます。 -
Distinct(JSON プロパティ):distinct)MySQL は個別の値を検索するため、最初に一致する行が見つかったら、現在の行の組み合わせについてのそれ以上の行の検索を停止します。
-
FirstMatch((JSON プロパティ):tbl_name)first_match)準結合 FirstMatch 結合ショートカット戦略は、
tbl_nameに使用されます。 -
Full scan on NULL key(JSON プロパティ):message)これは、オプティマイザがインデックスルックアップアクセスメソッドを使用できない場合の代替の戦略として、サブクエリーの最適化で行われます。
-
Impossible HAVING(JSON プロパティ):message)HAVING句は常に false で、どの行も選択できません。 -
Impossible WHERE(JSON プロパティ):message)WHERE句は常に false で、どの行も選択できません。 -
Impossible WHERE noticed after reading const tables(JSON プロパティ):message)MySQL はすべての
const(およびsystem) テーブルを読み取り、WHERE句が常に false であることを通知します。 -
LooseScan((JSON プロパティ):m..n)message)準結合 LooseScan 戦略が使用されます。
mおよびnは主要な部品番号です。 -
No matching min/max row(JSON プロパティ):message)SELECT MIN(...) FROM ... WHEREなどのクエリーの条件を満たす行がありません。condition -
no matching row in const table(JSON プロパティ):message)結合のあるクエリーで、空のテーブルまたは一意のインデックス条件を満足する行がないテーブルがありました。
-
No matching rows after partition pruning(JSON プロパティ):message)DELETEまたはUPDATEに対し、オプティマイザはパーティションのプルーニング後に削除または更新するものが何も見つかりませんでした。 それは、SELECTステートメントのImpossible WHEREに意味が似ています。 -
No tables used(JSON プロパティ):message)クエリーに
FROM句がないか、FROM DUAL句があります。INSERTまたはREPLACEステートメントで、SELECTパートがない場合に、EXPLAINにこの値が表示されます。 たとえば、EXPLAIN INSERT INTO t VALUES(10)に対して、それはEXPLAIN INSERT INTO t SELECT 10 FROM DUALと同等であるために表示されます。 -
Not exists(JSON プロパティ):message)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にならないことがわかっているため、同じid値を持つt2内の残りの行をスキャンしません。 つまり、t1の各行について、MySQL は、t2内の実際に一致する行数にかかわらず、t2内の単一のルックアップのみを実行する必要があります。MySQL 8.0.17 以降では、
NOT IN (またはsubquery)NOT EXISTS (形式のsubquery)WHERE条件が内部的にアンチ結合に変換されたことを示すこともできます。 これにより、サブクエリーが削除され、そのテーブルが最上位のクエリーの計画に追加され、コスト計画が改善されます。 準結合とアンチ結合をマージすることで、オプティマイザは実行計画内のテーブルの順序をより自由に変更できるため、計画が高速になる場合があります。特定のクエリーに対してアンチ結合変換が実行されるタイミングを確認するには、
EXPLAINの実行後にSHOW WARNINGSからMessageカラムを確認するか、EXPLAIN FORMAT=TREEの出力で確認します。注記アンチ結合は、準結合
を補完したものです。 アンチ結合では、table_aJOINtable_bONconditionconditionに一致する行がtable_bにないtable_aのすべての行が返されます。 -
Plan isn't ready yet(JSON プロパティ): none)この値は、オプティマイザが名前付き接続で実行中のステートメントの実行計画の作成を終了していない場合に、
EXPLAIN FOR CONNECTIONで発生します。 実行計画の出力が複数の行で構成されている場合、オプティマイザが完全な実行計画を決定する進行状況に応じて、そのいずれかまたはすべてがこのExtra値を持つ可能性があります。 -
Range checked for each record (index map:(JSON プロパティ) :N)message)MySQL は使用に適したインデックスを見つけられませんでしたが、前のテーブルからのカラム値がわかったあとに、いくつかのインデックスが使用できることがわかりました。 以前のテーブルの行の組み合わせごとに、MySQL は
rangeまたはindex_mergeアクセスメソッドを使用して、行を取得できるかどうかをチェックします。 これは、非常に高速ではありませんが、インデックスがまったくない結合の実行より高速です。 前のテーブルのすべてのカラム値がわかっており、定数とみなされることを除き、適用基準は、セクション8.2.1.2「range の最適化」とセクション8.2.1.3「インデックスマージの最適化」で説明されているとおりです。インデックスは、テーブルの
SHOW INDEXに示される同じ順序で 1 から番号付けされます。 インデックスマップ値Nは、候補となるインデックスを示すビットマスク値です。 たとえば、0x19(バイナリ 11001) の値は、インデックス 1、4、および 5 が考慮されることを意味します。 -
Recursive(JSON プロパティ):recursive)これは、行が再帰的共通テーブル式の再帰的
SELECT部分に適用されることを示します。 セクション13.2.15「WITH (共通テーブル式)」を参照してください。 -
Rematerialize(JSON プロパティ):rematerialize)Rematerialize (X,...)は、TテーブルのEXPLAIN行に表示されます。Xは、Tの新しい行が読み取られたときに再実体化がトリガーされるラテラル導出テーブルです。 例:SELECT ... FROM t, LATERAL (derived table that refers to t) AS dt ...導出テーブルの内容は、上位クエリーによって
tの新しい行が処理されるたびに最新になるように再実体化されます。 -
Scanned(JSON プロパティ):Ndatabasesmessage)これは、セクション8.2.3「INFORMATION_SCHEMA クエリーの最適化」に説明するように、サーバーが
INFORMATION_SCHEMAテーブルのクエリーを処理する際に実行するディレクトリスキャンの数を示します。Nの値は 0、1、またはallです。 -
Select tables optimized away(JSON プロパティ):message)オプティマイザは、1) 最大 1 つの行を戻す必要があると判断しました。2) この行を生成するには、確定的な行セットを読み取る必要があります。 読取り対象の行を最適化フェーズ中 (インデックス行の読取りなど) に読み取ることができる場合、クエリーの実行中にテーブルを読み取る必要はありません。
最初の条件は、クエリーが暗黙的にグループ化されるときに満たされます (集計関数は含まれますが、
GROUP BY句は含まれません)。 2 番目の条件は、使用されるインデックスごとに 1 つの行検索が実行されるときに満たされます。 読み取られるインデックスの数によって、読み取る行数が決まります。暗黙的にグループ化された次のクエリーについて考えてみます:
SELECT MIN(c1), MIN(c2) FROM t1;あるインデックス行を読み取ることで
MIN(c1)を取得でき、別のインデックスからある行を読み取ることでMIN(c2)を取得できるとします。 つまり、カラムc1およびc2ごとに、カラムがインデックスの最初のカラムであるインデックスが存在します。 この場合、2 つの決定的な行を読み取ることによって生成された 1 つの行が返されます。読み取る行が決定的でない場合、この
Extra値は発生しません。 次のクエリーについて考えてみます:SELECT MIN(c2) FROM t1 WHERE c1 <= 10;(c1, c2)がカバーインデックスであるとします。 このインデックスを使用して、c1 <= 10のすべての行をスキャンし、c2の最小値を検索する必要があります。 対照的に、次のクエリーについて考えてみます:SELECT MIN(c2) FROM t1 WHERE c1 = 10;この場合、
c1 = 10の最初のインデックス行には、c2の最小値が含まれます。 返される行を生成するには、1 つの行のみを読み取る必要があります。テーブルごとに正確な行数を保持するストレージエンジン (
MyISAMなど、InnoDBは保持しない) の場合、WHERE句が欠落しているか常に true で、GROUP BY句がないCOUNT(*)クエリーに対してこのExtra値が発生することがあります。 (これは暗黙的にグループ化されたクエリーのインスタンスであり、ストレージエンジンは確定的な行数を読み取ることができるかどうかに影響します。) -
Skip_open_table,Open_frm_only,Open_full_table(JSON プロパティ):message)これらの値は、
INFORMATION_SCHEMAテーブルのクエリーに適用されるファイルオープンの最適化を示します。Skip_open_table: テーブルファイルを開く必要はありません。 この情報はデータディクショナリからすでに使用可能です。Open_frm_only: テーブル情報を読み取る必要があるのはデータディクショナリのみです。Open_full_table: 最適化されていない情報参照。 テーブル情報は、データディクショナリから、およびテーブルファイルを読み取ることによって読み取る必要があります。
-
Start temporary、End temporary(JSON プロパティ):message)これは、準結合重複除去ストラテジの一時テーブルの使用を示します。
-
unique row not found(JSON プロパティ):message)SELECT ... FROMなどのクエリーの場合に、テーブルにtbl_nameUNIQUEインデックスまたはPRIMARY KEYの条件を満たす行がありません。 -
Using filesort(JSON プロパティ):using_filesort)MySQL はソート順で行を取得する方法を見つけるために、追加のパスを実行する必要があります。 ソートは、結合型に従ってすべての行を進み、ソートキーと
WHERE句に一致するすべての行について行へのポインタを格納して実行されます。 次にキーがソートされ、ソート順で行が取得されます。 セクション8.2.1.16「ORDER BY の最適化」を参照してください。 -
Using index(JSON プロパティ):using_index)実際の行を読み取るための追加のシークを実行する必要がなく、インデックスツリーの情報のみを使用して、テーブルからカラム情報が取得されます。 この戦略は、クエリーで単一のインデックスの一部であるカラムのみを使用している場合に使用できます。
ユーザー定義のクラスタ化されたインデックスを持つ
InnoDBテーブルの場合、そのインデックスはExtraカラムにUsing indexがない場合でも使用できます。 これは、typeがindexでkeyがPRIMARYの場合です。 -
Using index condition(JSON プロパティ):using_index_condition)インデックスタプルにアクセスし、まずそれらをテストして、すべてのテーブル行を読み取るかどうかを判断することによって、テーブルが読み取られます。 このように、必要でないかぎり、すべてのテーブル行の読み取りを遅延 (「プッシュダウン」) するためにインデックス情報が使用されます。 セクション8.2.1.6「インデックスコンディションプッシュダウンの最適化」を参照してください。
-
Using index for group-by(JSON プロパティ):using_index_for_group_by)Using indexテーブルアクセスメソッドと同様に、Using index for group-byは MySQL が、実際のテーブルへの追加のディスクアクセスをせずに、GROUP BYまたはDISTINCTクエリーのすべてのカラムを取得するために使用できるインデックスを見つけたことを示します。 さらに、各グループに対して、少数のインデックスエントリだけが読み取られるように、インデックスがもっとも効率的に使われます。 詳細は、セクション8.2.1.17「GROUP BY の最適化」を参照してください。 -
Using index for skip scan(JSON プロパティ):using_index_for_skip_scan)スキップスキャンアクセスメソッドが使用されていることを示します。 スキャン範囲アクセス方法のスキップを参照してください。
-
Using join buffer (Block Nested Loop),Using join buffer (Batched Key Access),Using join buffer (hash join)(JSON プロパティ):using_join_buffer)初期の結合からのテーブルは、部分ごとに結合バッファーに読み込まれ、それらの行がバッファーから使用されて、現在のテーブルとの結合が実行されます。
(Block Nested Loop)ではブロックネスト - ループアルゴリズムが使用され、(Batched Key Access)ではバッチキーアクセスアルゴリズムが使用され、(hash join)ではハッシュ結合が使用されます。 つまり、EXPLAIN出力の前の行にあるテーブルのキーがバッファされ、Using join bufferが表示される行で表されるテーブルから一致する行がバッチでフェッチされます。JSON 形式の出力では、
using_join_bufferの値は常にBlock Nested Loop、Batched Key Accessまたはhash joinのいずれかです。ハッシュ結合は、MySQL 8.0.18 以降で使用できます。Block Nested-Loop アルゴリズムは、MySQL 8.0.20 以降の MySQL リリースでは使用されません。 これらの最適化の詳細は、セクション8.2.1.4「ハッシュ結合の最適化」 および Block Nested Loop 結合アルゴリズム を参照してください。
バッチキーアクセスアルゴリズムの詳細は、Batched Key Access 結合 を参照してください。
-
Using MRR(JSON プロパティ):message)テーブルは Multi-Range Read 最適化戦略を使用して読み取られます。 セクション8.2.1.11「Multi-Range Read の最適化」を参照してください。
-
Using sort_union(...),Using union(...),Using intersect(...)(JSON プロパティ):message)これらは、
index_merge結合タイプのインデックススキャンのマージ方法を示す特定のアルゴリズムを示します。 セクション8.2.1.3「インデックスマージの最適化」を参照してください。 -
Using temporary(JSON プロパティ):using_temporary_table)クエリーを解決するために、MySQL は結果を保持する一時テーブルを作成する必要があります。 これは一般に、クエリーに、カラムを異なって一覧表示する
GROUP BY句とORDER BY句が含まれる場合に発生します。 -
Using where(JSON プロパティ):attached_condition)WHERE句は、次のテーブルに対して照合されるか、またはクライアントに送信される行を制限するために使用されます。 具体的にテーブルからすべての行をフェッチするか、調査する意図がないかぎり、Extra値がUsing whereでなく、テーブル結合型がALLまたはindexである場合、クエリーに何らかの誤りがある可能性があります。JSON 形式の出力では、
Using whereに直接対応するものはありません。attached_conditionプロパティには、使用されるWHERE条件が含まれます。 -
Using where with pushed condition(JSON プロパティ):message)この項目は
NDBテーブルのみに適用されます。 つまり、NDB Cluster は条件プッシュダウン最適化を使用して、インデックスなしカラムと定数の間の直接比較の効率を向上させています。 そのような場合、条件がクラスタのデータノードに「プッシュダウン」され、すべてのデータノードで同時に評価されます。 これにより、一致しない行をネットワーク経由で送る必要がなくなり、コンディションプッシュダウンを使用できるが使用しない場合より、そのようなクエリーを 5 - 10 倍高速化できます。 詳細は、セクション8.2.1.5「エンジンコンディションプッシュダウンの最適化」を参照してください。 -
Zero limit(JSON プロパティ):message)クエリーに
LIMIT 0句があり、行を選択できません。
EXPLAIN 出力の rows カラムの値の積を取得することで、結合がどの程度適しているかを示す適切な目安を得ることができます。 これは、クエリーを実行するために MySQL が調査する必要がある行数を大ざっぱに示すはずです。 max_join_size システム変数によってクエリーを制限する場合、この行の積は、どの複数テーブル SELECT ステートメントを実行し、どれを中止するかを判断するためにも使用されます。 セクション5.1.1「サーバーの構成」を参照してください。
次の例は、EXPLAIN によって得られた情報に基づいて、複数テーブル結合を段階的に最適化する方法を示しています。
ここに示す SELECT ステートメントがあり、EXPLAIN を使用して調査するつもりであるとします。
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;
この例では次のように想定しています。
-
比較対象のカラムは次のように宣言されています。
Table カラム データ型 ttActualPCCHAR(10)ttAssignedPCCHAR(10)ttClientIDCHAR(10)etEMPLOYIDCHAR(15)doCUSTNMBRCHAR(15) -
テーブルには次のインデックスがあります。
Table インデックス ttActualPCttAssignedPCttClientIDetEMPLOYID(主キー)doCUSTNMBR(主キー) 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 (index map: 0x23)
各テーブルの 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 (index map: 0x1)
et_1 ALL PRIMARY NULL NULL NULL 74
Range checked for each record (index map: 0x1)
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 句で異なる順序でテーブルを一覧表示してみるとパフォーマンスを改善できる可能性があります。 (ただし、STRAIGHT_JOIN では準結合変換が無効になるため、インデックスの使用が妨げられる場合があります。 セクション8.2.2.1「準結合変換による IN および EXISTS サブクエリー述語の最適化」を参照してください。)
場合によっては、サブクエリーで EXPLAIN SELECT を使用するときに、データを変更するステートメントを実行できることもあります。詳細については、セクション13.2.11.8「導出テーブル」を参照してください。