EXPLAIN tbl_name か EXPLAIN SELECT select_options
        EXPLAIN tbl_name は、DESCRIBE
        tbl_name または SHOW COLUMNS FROM
        tbl_name のシノニムです。
      
        キーワード EXPLAIN を
        SELECT
        ステートメントの前に置いた場合、MySQL
        によってテーブルの結合状況と順序に関する情報が提供され、テーブルの
        SELECT
        の処理方法が説明されます。
      
        EXPLAIN
        を利用すると、より速くレコードを検索する
        SELECT
        を得るために、どの時テーブルにインデックスを追加しなければならないかを確認できます。
      
        最適化方法の選択に影響を及ぼすキーの、カーディナリティなどのテーブル統計を更新するために、ANALYZE
        TABLE
        を定期的に実行する必要があります。 See
        項4.6.2. 「ANALYZE TABLE 構文」。
      
        また、オプティマイザが、テーブルを最適な順序で結合しているかどうかも確認することができます。
        オプティマイザが特定の順番で結合を行うように強制するには、SELECT
        ステートメントに STRAIGHT_JOIN
        節を追加します。
      
        非単純結合の場合、EXPLAIN は
        SELECT
        ステートメントで使用される各テーブルに関する情報を返します。
        テーブルは、読み取られた順序に従って一覧表示されます。
        MySQL
        は、単一スイープ多結合メソッドを使用してすべての結合を解決します。これは、MySQL
        が最初のテーブルからレコードを読み取ってから、第
        2 のテーブル、第 3
        のテーブルといった順序で、一致するレコードの検索を行うことを意味します。
        すべてのテーブルの処理が終わると、選択したカラムと、さらに一致レコードがあるテーブルが検索されるまでのテーブル一覧のバックトラックが出力されます。
        次のレコードはこのテーブルから読み取られ、処理が次のテーブルから続行されます。
      
        MySQL バージョン 4.1 では、EXPLAIN
        出力が変更され、UNION
        ステートメント、サブクエリ、派生テーブルなどの構造での機能が改善されています。最も重要なことは、id
        と select_type という 2
        つの新しいカラムが追加されたことです。
      
        EXPLAIN
        の出力は、次のカラムで構成されます。
      
            id
          
            SELECT に割り当てられた
            ID。クエリ内におけるこの
            SELECT の順序番号。
          
            select_type
          
            SELECT
            節の種類、次のいずれかが示される。
          
                SIMPLE
              
                単純な
                SELECT(UNION
                やサブクエリを使用しない)。
              
                PRIMARY
              
                最外部の SELECT
              
                UNION
              
                UNION 内の第 2
                およびそれ以降の SELECT
                ステートメント。
              
                DEPENDENT UNION
              
                UNION 内の第 2
                およびそれ以降の SELECT
                ステートメント、外側のサブクエリに依存する。
              
                SUBQUERY
              
                サブクエリ内の第 1 SELECT。
              
                DEPENDENT SUBQUERY
              
                第 1
                SELECT、外側のサブクエリに依存する。
              
                DERIVED
              
                派生テーブル
                SELECT(FROM
                節内のサブクエリ)。
              
            table
          
結果を得るために参照するテーブル。
            type
          
結合型。各結合型を最適なものから順に紹介する。
                system
              
                1 レコードのみで構成されるテーブル(=
                システムテーブル)。これは、const
                結合型の特殊なケースである。
              
                const
              
                テーブルに、一致するレコードが最大で 1
                つあり、クエリの開始時に読み取られる。レコードが
                1
                つしかないため、このレコードのカラムの値はオプティマイザによって定数と見なされる。const
                テーブルは、1
                回しか読み取られないため、非常に高速である。
              
                const
                は、PRIMARY/UNIQUE
                キーを定数と比較する場合に使用される。
              
SELECT * FROM const_table WHERE primary_key=1; SELECT * FROM const_table WHERE primary_key_part1=1 AND primary_key_part2=2;
                eq_ref
              
                前のテーブルのレコードの組み合わせのそれぞれに対して、このテーブルから
                1
                レコードずつ読み取られる。これは、const
                型以外で最適な結合型である。結合でインデックスのすべての部分が使用され、このインデックスが
                UNIQUE または PRIMARY
                KEY である場合に使用される。
              
                =
                演算子と比較されるインデックスの張られたカラムには、eq_ref
                を使用できる。比較対象のアイテムは定数でも、このテーブル以前に読み取られたテーブルのカラムを使用する式でもかまわない。
              
                下記の例では、ref_table で
                eq_ref が使用される。
              
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
              
                前のテーブルのレコードの組み合わせのそれぞれに対して、インデックス値にマッチするすべてのレコードがこのテーブルから読み取られる。ref
                は、インデックスの左端の先頭部分のみが結合で使用される場合、またはインデックスが
                UNIQUE や PRIMARY
                KEY
                ではない場合(すなわち、この結合において、インデックス値から1つのレコードをSELECTできない場合)に使用される。この結合型は、使用されるインデックスと一致するレコードが数レコードしかない場合に適している。
              
                =
                演算子と比較されるインデックスが張られたカラムには、ref
                が使用される。
              
                下記の例では、ref_table で
                ref が示される。
              
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;
                ref_or_null
              
                ref
                と同様だが、NULL
                を使用したレコードの補足検索も追加で実行される。
                See 項5.2.5. 「MySQL による IS NULL の最適化」。
              
SELECT * FROM ref_table WHERE key_column=expr OR key_column IS NULL;
この結合型の最適化は、MySQL 4.1.1 の新機能で、主としてサブクエリを解決する場合に使用される。
                range
              
                インデックスを使用して、一定の範囲にあるレコードのみが取り出される。key
                カラムに使用されるインデックスが示される。
                key_len
                には使用される最長のインデックス部分が記載される。
                この型では、ref カラムが
                NULL になる。
              
                range
                は、インデックスを張っているカラムが
                =、<>、>、>=、<、<=、IS
                NULL、<=>、BETWEEN、および
                IN
                を使用して定数と比較される場合に使用される。
              
SELECT * FROM range_table WHERE key_column = 10; SELECT * FROM range_table WHERE key_column BETWEEN 10 and 20; SELECT * FROM range_table WHERE key_column IN (10,20,30); SELECT * FROM range_table WHERE key_part1= 10 and key_part2 IN (10,20,30);
                index
              
                これは、インデックスツリーのみがスキャンされる点を除いて
                ALL
                と同じである。一般にインデックスファイルはデータファイルより小さいため、通常は
                ALL より高速である。
              
これは、クエリで 1 インデックスの構成部分であるカラムのみが使用される場合にのみ使用される。
                ALL
              
                前のテーブルのレコードの組み合わせのそれぞれに対して、フルテーブルスキャンが実行される。一般に、テーブルが
                const の指定がない第 1
                テーブルの場合には適さず、その他の場合はすべて非常に不適である。通常は、さらにインデックスを追加することで
                ALL
                を回避し、定数値または以前のテーブルのカラム値を基準にレコードを取り出すようにすることができる。
              
            possible_keys
          
            possible_keys
            カラムは、このテーブル内のレコードの検索に
            MySQL
            で使用可能なインデックスを示す。このカラムはテーブルの順序にはまったく依存しないことに注意する。すなわち、possible_keys
            のキーの一部は、生成されたテーブルの順序では事実上使用できないことになる。
          
            このカラムが NULL
            の場合は、対応するインデックスがない。この場合は、WHERE
            節でインデックス作成に適するカラムを 1
            つ以上参照しているかどうかを調べることでクエリのパフォーマンスを改善できる。参照している場合は適切なインデックスを作成し、再度
            EXPLAIN
            を使用してクエリをチェックする。 See
            項6.5.4. 「ALTER TABLE 構文」。
          
            テーブルにあるインデックスを調べるには
            SHOW INDEX FROM tbl_name
            を使用する。
          
            key
          
            key カラムは、MySQL
            が実際に使用を決定したキー(インデックス)を示す。選択されたインデックスがない場合、このキーは
            NULL になる。MySQL で
            possible_keys
            カラムに記載されたキーが使用されるように強制するには、クエリで
            USE KEY/IGNORE KEY を使用する。 See
            項6.4.1. 「SELECT 構文」。
          
            また、テーブルで myisamchk
            --analyze(see
            項4.5.6.1. 「myisamchk 起動構文」)または
            ANALYZE TABLE(see
            項4.6.2. 「ANALYZE TABLE 構文」)を実行することも、オプティマイザでより適したインデックスを選択する際に役立つ。
          
            key_len
          
            key_len カラムは、MySQL
            が使用を決定したキーの長さを示す。key
            が NULL の場合、この長さは
            NULL
            になる。これによって、複合キーで MySQL
            が実際に使用するパート数が示されることに注意する。
          
            ref
          
            ref
            カラムは、テーブルからレコードを選択する際に
            key
            とともに使用されるカラムまたは定数を示す。
          
            rows
          
            rows
            カラムは、クエリの実行に際して調べる必要があると
            MySQL
            によって判定されたレコードの数を示す。
          
            Extra
          
このカラムには、MySQL でどのようにクエリが解決されるかに関する追加情報が記載される。以下は、このカラムに記載できる各種テキスト文字列の説明である。
                Distinct
              
マッチした最初のレコードが検索されると、MySQL は現在のレコードの組み合わせによるその後のレコード検索を続行しないことを示す。
                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
                は t2.id
                ではないと認識され、t2
                内の同じ id
                を持つ残りのレコードのスキャンは行われない。言い換えると、t2
                にあるマッチするレコードの数に関わらず、MySQL
                で実行が必要なことは t1
                のレコードのそれぞれに対して、t2
                のルックアップを 1
                回実行することだけである。
              
                range checked for each record (index map:
                #)
              
MySQL で使用に適した実際のインデックスを検索できなかったことを示す。代替として、先行テーブルのレコードの組み合わせのそれぞれに対して、使用するインデックス(存在する場合)のチェックが実行され、このインデックスがテーブルからのレコードの取り出しに使用される。非常に高速ではないが、インデックスなしの結合と比較すると高速である。
                Using filesort
              
                レコードをソートして取り出す方法を決定するには、MySQL
                はパスを余分に実行しなくてはならないことを示す。
                join type
                に従ってすべてのレコードをスキャンし、WHERE
                条件に一致する全てのレコードに、ソートキー
                +
                行ポインタを格納して、ソートは実行される。
                その後キーがソートされる。
                最後に、ソートされた順にレコードが取り出される。
              
                Using index
              
インデックスツリーの情報のみを使用してカラム情報がテーブルから取り出され、実際のレコードを読み取るその後の検索を実行する必要がないことを示す。これは、そのテーブルで使用されたカラムがすべて同一インデックスの構成部分である場合に実行できる。
                Using temporary
              
                クエリの解決に MySQL
                で結果を保持するテンポラリテーブルの作成が必要であることを示す。これは一般に、GROUP
                BY
                を実行したカラムセットと異なるカラムセットに対して
                ORDER BY
                を実行した場合に発生する。
              
                Using where
              
                次のテーブルとの一致が調べられるレコードまたはクライアントに送信されるレコードの限定に
                WHERE
                節が使用されることを示す。この情報がなく、テーブルの型が
                ALL または
                index
                である場合はクエリが正常に実行されないことがある(テーブルのすべてのレコードの取得や検査を意図していない場合)。
              
            クエリを最大限高速に実行する必要がある場合は、Using
            filesort と Using temporary
            に注意する必要がある。
          
        EXPLAIN 出力の rows
        カラムのすべての値を掛け算することで、結合がどの程度適しているかを示す指針を取得できます。これは、クエリの実行時に
        MySQL
        で調べる必要があるレコード数の概要を示します。この数値は、max_join_size
        変数でクエリを制限する際にも使用されます。
        See 項5.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,ClientID,ActualPC NULL NULL    NULL 3872
      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,ClientID,ActualPC NULL NULL NULL 3872    Using where
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 where
             ClientID,
             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 に示すことができます。
      
shell>myisamchk --analyze PATH_TO_MYSQL_DATABASE/ttshell>mysqladmin refresh
        これで結合が完全になり、EXPLAIN
        で以下の結果が生成されます。
      
table type   possible_keys key     key_len ref           rows Extra
tt    ALL    AssignedPC    NULL    NULL    NULL          3872 Using where
             ClientID,
             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
        結合オプティマイザの学習による推測であることに注意してください。クエリを最適化するには、この数値が実際に近いものであるかどうかを確認する必要があります。実際とかけ離れている場合は、SELECT
        ステートメントで STRAIGHT_JOIN
        を使用し、FROM
        節でテーブルの順序を変えて一覧表示してみるとパフォーマンスを改善できます。
      
This is a translation of the MySQL Reference Manual that can be found at dev.mysql.com. The original Reference Manual is in English, and this translation is not necessarily as up to date as the English version.

