EXPLAIN
        ステートメントは
        DESCRIBE
        の同義語として使用するか、MySQL がどのように
        SELECT
        ステートメントを実行するかの情報が得られます。
      
            EXPLAIN
             は
            tbl_nameDESCRIBE
             または
            tbl_nameSHOW COLUMNS FROM
            
            の同義語です。
          tbl_name
EXPLAIN tbl_name
            SELECT
            ステートメントの前にキーワード
            EXPLAIN を
            置いた場合、MySQL
            はクエリーの実行計画に関するオプティマイザからの情報を表示します。つまり、テーブルの結合状況と順序に関する情報など、SELECT
            の処理方法が説明されます。
EXPLAIN [EXTENDED | PARTITIONS] SELECT select_options
            EXPLAIN
            PARTITIONS は MySQL 5.1.5
            から提供されています。区割りされたテーブルのクエリーを調べるときに便利です。詳細については、Obtaining Information About Partitionsをご参照ください。
          
        この節では、クエリー実行情報を得るための
        EXPLAIN の 2
        つめの使用方法を記述します。項8.3.2. 「EXPLAIN 構文」
        も参照してください。DESCRIBE
        と SHOW COLUMNS
        ステートメントの詳細については、項8.3.1. 「DESCRIBE 構文」と項8.5.5.6. 「SHOW COLUMNS 構文」を参照してください。
      
        
        EXPLAIN
        を利用すると、より速くレコードを検索する
        SELECT
        を得るために、テーブルのどこにインデックスを追加しなければならないかを確認できます。また、EXPLAIN
        を使用して、オプティマイザがテーブルを最適な順序で結合しているかどうかも確認することができます。特定の順番で結合を行うようにオプティマイザにヒントを与えるには、ただ
        SELECT
        でステートメントを始めるのではなく、SELECT
        ステートメントに
        STRAIGHT_JOIN
        節を追加します。詳細は、項8.2.8. 「SELECT 構文」
        を参照してください。
      
        最適化方法の選択に影響を及ぼすキーの、カーディナリティなどのテーブル統計を更新するために、ANALYZE
        TABLE
        を定期的に実行する必要があります。項8.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 RESULT | UNIONの結果。 | 
| SUBQUERY | サブクエリー内の第一 SELECT。 | 
| DEPENDENT SUBQUERY | 第
                    1 SELECT、外側のサブクエリーに依存する。 | 
| DERIVED | 派生テーブル SELECT(FROM節内のサブクエリー) | 
| UNCACHEABLE SUBQUERY | 結果がキャッシュされず、外側のクエリーの各行ごとに再評価されるサブクエリー。 | 
| UNCACHEABLE UNION | キャッシュ不可能なサブクエリーの UNION内の第 2 およびそれ以降の SELECT
                    (UNCACHEABLE
                    SUBQUERYを参照) | 
            DEPENDENT
            は主に、相互に関係するサブクエリーの使用を表します。項8.2.9.7. 「相関サブクエリー」
            を参照してください。
          
            「依存型サブクエリー」の評価は
            UNCACHEABLE SUBQUERY
            評価とは異なります。「DEPENDENT
            SUBQUERY」
            に関しては、外側コンテキストの変数の値が異なるたびに、一回のみサブクエリーの再評価が行われます。UNCACHEABLE
            SUBQUERY
            に関しては、サブクエリーは外側コンテキストの各行ごとに再評価されます。サブクエリーのキャッシュアビリティは項4.5.5.1. 「クエリキャッシュの動作」で記述される制限によります。たとえば、ユーザー変数に参照することでサブクエリーがキャッシュできなくなります。
          
            table
          
結果を得るために参照するテーブル。
            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;
                前のテーブルのレコードの組み合わせのそれぞれに対して、このテーブルから
                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
                は、インデックスの左端の接頭辞のみが結合で使用される場合、またはインデックスが
                PRIMARY KEY や
                UNIQUE
                インデックスではない場合
                (すなわち、この結合において、インデックス値から
                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;
                FULLTEXT
                インデックスを使用して結合が実行されます。
              
                ref
                と同様だが、NULL
                を使用したレコードの補足検索も追加で実行される。この結合型の最適化は主としてサブクエリーを解決する場合に使用される。下記の例では、MySQL
                は ref_table で
                ref_or_null
                が使用される。
              
SELECT * FROMref_tableWHEREkey_column=exprORkey_columnIS NULL;
                項4.2.8. 「IS NULL 最適化」
                を参照してください。
              
                この結合型はインデックス併合最適化が使用されたことを示しています。この場合、出力行の
                key
                カラムは使用されたインデックスのリストが含まれ、key_len
                には使用されたインデックスの最長キーパートが含まれます。詳細は
                項4.2.6. 「インデックス結合最適化」
                をご覧ください。
              
                この型は、下記のフォームで
                IN
                サブクエリーの代わりに、ref
                を使用します。
              
valueIN (SELECTprimary_keyFROMsingle_tableWHEREsome_expr)
                unique_subquery
                は、効率化のためサブクエリーの代わりをつとめるインデックスルックアップ関数です。
              
                この結合型は
                unique_subquery
                に似ています。IN
                サブクエリーの代わりに使用されますが、次の形式のサブクエリーで一意でないインデックスで使用できます。
              
valueIN (SELECTkey_columnFROMsingle_tableWHEREsome_expr)
                インデックスを使用して、一定の範囲にあるレコードのみが取り出される。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);
                これは、インデックスツリーのみがスキャンされる点を除いて
                ALL
                と同じである。一般にインデックスファイルはデータファイルより小さいため、通常は
                ALL
                より高速である。
              
MySQL は、クエリーで 1 インデックスの構成部分であるカラムのみが使用される場合にのみ使用できます。
                前のテーブルのレコードの組み合わせのそれぞれに対して、フルテーブルスキャンが実行される。一般に、テーブルが
                const
                の指定がない第 1
                テーブルの場合には適さず、その他の場合はすべて非常に不適である。通常は、さらにインデックスを追加することで
                ALL
                を回避し、定数値または以前のテーブルのカラム値を基準にレコードを取り出すようにすることができる。
              
            possible_keys
          
            possible_keys
            カラムは、このテーブル内のレコードの検索に
            MySQL
            で使用可能なインデックスを示す。このカラムは
            EXPLAIN
            からの出力により表示されたテーブルの順序にはまったく依存しないことに注意する。すなわち、possible_keys
            のキーの一部は、生成されたテーブルの順序では事実上使用できないことになる。
          
            このカラムが NULL
            の場合は、対応するインデックスがない。t
            この場合は、WHERE
            節でインデックス設定に適するカラムを 1
            つ以上参照しているかどうかを調べることでクエリーのパフォーマンスを改善できる。参照している場合は適切なインデックスを作成し、再度
            EXPLAIN
            を使用してクエリーを確認する。項8.1.7. 「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
            を使用する。項8.2.8.2. 「インデックスヒントの構文」
            を参照してください。
          
            MyISAM
            テーブルには、ANALYZE
            TABLE
            を実行することでオプティマイザでより適したインデックスを選択する際役立つ。MyISAM
            テーブルに関しても、myisamchk
            --analyze
            は同じことをします。項8.5.2.1. 「ANALYZE TABLE 構文」、MyISAM Table Maintenance and Crash Recovery
            を参照してください。
          
            key_len
          
            key_len
            カラムは、MySQL
            が実際に使用を決定したキーの長さを示す。key
            が NULL
            の場合、この長さは
            NULL
            になる。key_len
            の値によって、複合キーで MySQL
            が実際に使用するパート数が示されることに注意する。
          
            ref
          
            ref
            カラムは、テーブルからレコードを選択する際に
            key
            とともに使用されるカラムまたは定数を示す。
          
            rows
          
            rows
            カラムは、クエリーの実行に際して調べる必要があると
            MySQL
            によって判定されたレコードの数を示す。
          
            InnoDB
            テーブルの場合、これは推定値であり、常に正確というわけではありません。
          
            filtered
          
            filtered
            カラムはテーブルの状態によってフィルターされるテーブル行のパーセンテージ
            (予想)
            を表示します。つまり、rows
            は検査された行の予想数を表示し、rows
            × filtered /
            100
            は前のテーブルと結合する行の数を表示します。EXPLAIN
            EXTENDED
            を使用すると、このカラムが表示されます。(MySQL
            5.1.12 の新しい機能です)。
          
            Extra:
          
            このカラムには、MySQL
            でどのようにクエリーが解決されるかに関する追加情報が記載される。下記のリストはこのカラムで表示される可能性のある値を説明する。クエリーの速度をできるかぎり上げたい場合は、Using
            filesort と Using
            temporary の
            Extra
            値に注目してください。
          
                Distinct
              
マッチした最初のレコードが検索されると、MySQL は現在のレコードの組み合わせによるその後のレコード検索を続行しないことを示す。
                Full scan on NULL key
              
これは、オプティマイザでインデックス検索アクセスメソッドを使用できない場合の代替方針として、サブクエリーの最適化に使用されます。
                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
                の確認が実行され、このインデックスがテーブルからのレコードの取り出しに使用される。非常に高速ではないが、インデックスなしの結合と比較すると高速である。適用基準は項4.2.5. 「Range 最適化」と項4.2.6. 「インデックス結合最適化」で説明されています。ただし、これは前テーブルのすべてのカラム値が知られており、定数であるという前提においてです。
              
                インデックスには、テーブルの
                SHOW
                INDEX で表示されるのと同じ順序で
                1
                から番号がふられます。インデックスマップ値
                N
                は、どのインデックスが対象になるかを示すビットマスク値です。たとえば、0x19
                (2 進数の 11001) という値は、インデックス
                1、4、および 5
                が対象になることを示します。
              
                Scanned
                
              N databases
                サーバーが
                INFORMATION_SCHEMA
                テーブルのクエリーを処理する際に実行するディレクトリスキャンの数を示します。詳細については、項4.2.20. 「INFORMATION_SCHEMA 最適化」を参照してください。N
                の値は 0、1、または
                all です。
              
                Select tables optimized
                away
              
                クエリーは
                MyISAM
                用に、インデックスで解決された集約ファンクション
                (MIN()、MAX())
                そして COUNT(*)
                があり、GROUP BY
                節は含みませんでした。オプティマイザは
                1
                つの行のみが返されるべきと判断しました。
              
                Skip_open_table、Open_frm_only、Open_trigger_only、Open_full_table
              
                これらの値は、INFORMATION_SCHEMA
                テーブルのクエリーに適用する、ファイルを開く処理の最適化を示します。詳細については、項4.2.20. 「INFORMATION_SCHEMA 最適化」を参照してください。
              
                    Skip_open_table:
                    テーブルファイルを開く必要はありません。データベースディレクトリをスキャンすることによってクエリーで情報はすでに取得されています。
                  
                    Open_frm_only:
                    テーブルの
                    .frm
                    ファイルのみ開く必要があります。
                  
                    Open_trigger_only:
                    テーブルの
                    .TRG
                    ファイルのみ開く必要があります。
                  
                    Open_full_table:
                    情報検索は最適化されません。.frm、.MYD、および
                    .MYI
                    ファイルを開く必要があります。
                  
                Using filesort
              
                レコードをソートして取り出す方法を決定するには、MySQL
                はパスを余分に実行しなくてはならないことを示す。join
                type
                に従ってすべてのレコードをスキャンし、WHERE
                条件に一致するすべてのレコードに、ソートキー
                +
                行ポインタを格納して、ソートは実行される。その後キーがソートされる。最後に、ソートされた順にレコードが取り出される。項4.2.13. 「ORDER BY 最適化」
                を参照してください。
              
                Using index
              
インデックスツリーの情報のみを使用してカラム情報がテーブルから取り出され、実際の行を読み取るその後の検索を実行する必要がないことを示す。この方針は、クエリーで単一のインデックスの構成部分であるカラムのみが使用される場合に使用できます。
                ユーザー定義のクラスタ化されたインデックスを持つ
                InnoDB
                テーブルの場合、そのインデックスは
                Extra カラムに
                Using index
                がない場合でも使用できます。type
                が
                index
                で key が
                PRIMARY
                の場合はこれに当てはまります。
              
                Using index for
                group-by
              
                Using index
                テーブルアクセスメソッドに似て、Using
                index for group-by は MySQL
                が余分なディスクアクセスを実際のテーブルに行うことなく、GROUP
                BY または
                DISTINCT
                クエリーのカラムをすべて取得することができるインデックスを見つけたことを意味します。加えて、インデックスは各グループにとってもっとも効率的に使われるので、数種類のインデックスしか読まれません。詳細については、項4.2.14. 「GROUP BY 最適化」をご参照ください。
              
                Using join buffer
              
それまでに結合されたテーブルは部分ごとに結合バッファーに読み込まれ、それらのバッファー内の行を使用して、現在のテーブルとの結合が実行されます。
                Using
                sort_union(...)、Using
                union(...)、Using
                intersect(...)
              
                これらは
                index_merge
                結合型でインデックススキャンがどのように併合されるかを示しています。項4.2.6. 「インデックス結合最適化」
                を参照してください。
              
                Using temporary
              
                クエリーの解決に MySQL
                で結果を保持する一時テーブルの作成が必要であることを示す。これは一般に、GROUP
                BY
                を実行したカラムセットと異なるカラムセットに対して
                ORDER BY
                を実行した場合に発生する。
              
                Using where
              
                次のテーブルとの一致が調べられるレコードまたはクライアントに送信されるレコードの限定に
                WHERE
                節が使用されることを示す。この情報がなく、Extra
                の値が Using where
                ではなく、テーブルの型が
                ALL
                または
                index
                である場合はクエリーが正常に実行されないことがある
                (テーブルのすべてのレコードの取得や検査を意図していない場合)。
              
                Using where with pushed
                condition
              
                このアイテムは
                NDBCLUSTER
                テーブルにのみ適用されます。それは、MySQL
                Cluster
                がコンディションプッシュダウン最適化を使用して、インデックスのないカラムと定数の直接比較の効率化を図ることを意味します。そのような場合、条件はクラスタのデータノードに
                「プッシュダウン」
                され、すべてのデータノードで同時に評価されます。これは一致しない行をネットワーク上で送る必要をなくし、コンディションプッシュダウンを使える状態にあるが使用してないケースに比べて、クエリーの速度を
                5 - 10 倍に増やします。詳細は
                項4.2.7. 「コンディションプッシュダウン最適化」
                をご覧ください。
              
        EXPLAIN 出力の
        rows
        カラムのすべての値を掛け算することで、結合がどの程度適しているかを示す指針を取得できます。This
        これは、クエリーの実行時に MySQL
        で調べる必要があるレコード数の概要を示します。この数値は、max_join_size
        変数でクエリーを制限する際にも使用されるほか、どのマルチテーブル
        SELECT
        ステートメントを実行するか、あるいはアボートするかを判別します。項4.5.3. 「サーバーパラメータのチューニング」
        を参照してください。
      
        下記の例は、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;
この例では次のように想定しています。
比較対象のカラムは次のように宣言されています。
| テーブル | カラム | Data Type | 
| 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 (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
        節でテーブルの順序を変えて一覧表示してみるとパフォーマンスを改善できます。
      
        場合によっては、EXPLAIN
        SELECT
        をサブクエリーとともに使用するときに、データを変更するステートメントを実行できることもあります。詳細については、項8.2.9.8. 「FROM 節内のサブクエリー」を参照してください。
      

