Select type
提供:MySQL Practice Wiki
select_typeはどのようなコンテキストで、別の言い方をするとどのような種類のクエリによってテーブルが参照されるかを示す。クエリの種類とは、つまりJOIN、UNION、サブクエリとその組み合わせのことである。さらに別の言い方をすると、パーサーが構文解析をした結果を示すラベルであると言える。(以下の例ではworldデータベースを利用して解説している。)
目次 |
SIMPLE
UNIONやサブクエリがない場合はSIMPLEになる。例えば次のように。 <highlightSyntax language="mysql"> mysql> EXPLAIN SELECT * FROM Country WHERE Code='USA'; +----+-------------+---------+-------+---------------+---------+---------+-------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+---------+-------+---------------+---------+---------+-------+------+-------+ | 1 | SIMPLE | Country | const | PRIMARY | PRIMARY | 3 | const | 1 | | +----+-------------+---------+-------+---------------+---------+---------+-------+------+-------+ 1 row in set (0.00 sec) </highlightSyntax> JOINを行う場合でもselect_typeはSIMPLEになる。 <highlightSyntax language="mysql"> mysql> EXPLAIN SELECT * FROM Country,City WHERE Country.Code=City.CountryCode AND Country.Name LIKE 'A%'; +----+-------------+---------+--------+---------------+---------+---------+------------------------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+---------+--------+---------------+---------+---------+------------------------+------+-------------+ | 1 | SIMPLE | City | ALL | NULL | NULL | NULL | NULL | 4079 | | | 1 | SIMPLE | Country | eq_ref | PRIMARY | PRIMARY | 3 | world.City.CountryCode | 1 | Using where | +----+-------------+---------+--------+---------------+---------+---------+------------------------+------+-------------+ 2 rows in set (0.00 sec) </highlightSyntax>
PRIMARY
PRIMARYとなるのは次の2つのケース。
- UNIONで最も最初のSELECT。
- サブクエリで最も外側にあるSELECT。
- MySQL 6.0以降ではSemi-Join最適化が行われたサブクエリは全てPRIMARYとなる。
詳細は下記参照。
SUBQUERY
Correlatedでない(サブクエリと親クエリで相関関係のない)クエリにおいて、サブクエリ部分のselect_typeがSUBQUERYとなる。 <highlightSyntax language="mysql"> mysql> EXPLAIN SELECT * FROM Country WHERE Code = (SELECT CountryCode FROM City ORDER BY Population DESC LIMIT 1); +----+-------------+---------+-------+---------------+---------+---------+-------+------+----------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+---------+-------+---------------+---------+---------+-------+------+----------------+ | 1 | PRIMARY | Country | const | PRIMARY | PRIMARY | 3 | const | 1 | | | 2 | SUBQUERY | City | ALL | NULL | NULL | NULL | NULL | 4079 | Using filesort | +----+-------------+---------+-------+---------------+---------+---------+-------+------+----------------+ 2 rows in set (0.00 sec) </highlightSyntax> SUBQUERYは最初に評価されたときに一度だけ実行される。それ以降、結果はキャッシュされる。
DEPENDENT SUBQUERY
相関サブクエリにおけるサブクエリ部分。 <highlightSyntax language="mysql"> mysql> EXPLAIN SELECT Name, Capital FROM Country WHERE Population / 2 < (SELECT Population FROM City WHERE City.Id = Country.Capital); +----+--------------------+---------+--------+---------------+---------+---------+-----------------------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+--------------------+---------+--------+---------------+---------+---------+-----------------------+------+-------------+ | 1 | PRIMARY | Country | ALL | NULL | NULL | NULL | NULL | 239 | Using where | | 2 | DEPENDENT SUBQUERY | City | eq_ref | PRIMARY | PRIMARY | 4 | world.Country.Capital | 1 | | +----+--------------------+---------+--------+---------------+---------+---------+-----------------------+------+-------------+ 2 rows in set (0.00 sec) </highlightSyntax> 相関サブクエリになってない場合でも、MySQLのオプティマイザはIN句などを用いたサブクエリをDEPENDENT SUBQUERYと判断してしまうので注意が必要。 <highlightSyntax language="mysql"> mysql> EXPLAIN SELECT * FROM Country WHERE Code IN (SELECT CountryCode FROM City WHERE Population > 1000000); +----+--------------------+---------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+--------------------+---------+------+---------------+------+---------+------+------+-------------+ | 1 | PRIMARY | Country | ALL | NULL | NULL | NULL | NULL | 239 | Using where | | 2 | DEPENDENT SUBQUERY | City | ALL | NULL | NULL | NULL | NULL | 4079 | Using where | +----+--------------------+---------+------+---------------+------+---------+------+------+-------------+ 2 rows in set (0.00 sec) </highlightSyntax> これはIN→EXISTSという最適化が行われるためである。上記の例では、Code IN (SELECT CountryCode FROM City WHERE Population > 1000000)はEXISTS (SELECT 1 FROM City WHERE Population > 1000000 AND CountryCode = Country.Code)に書き直される。
DEPENDENT SUBQUERYでは、PRIMARYのSELECTにおいて外部クエリの検索条件が変化するごと(上記の例ではCodeの値が変化するごと)にサブクエリが評価されるので場合によってはとても遅い。
UNCACHEABLE SUBQUERY
実行するまで結果が分からないようなサブクエリ。例えばRAND()が検索条件に含まれているようなもので、如何なる場合も毎回評価されてしまうのでDEPENDENT SUBQUERYよりもコストが高い。
<highlightSyntax language="mysql"> mysql> EXPLAIN SELECT Name FROM Country WHERE Population > (SELECT Population FROM City WHERE ID = RAND()); +----+----------------------+---------+-------+---------------+------------+---------+------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+----------------------+---------+-------+---------------+------------+---------+------+------+--------------------------+ | 1 | PRIMARY | Country | ALL | NULL | NULL | NULL | NULL | 239 | Using where | | 2 | UNCACHEABLE SUBQUERY | City | index | NULL | Population | 4 | NULL | 4217 | Using where; Using index | +----+----------------------+---------+-------+---------------+------------+---------+------+------+--------------------------+ 2 rows in set (0.00 sec) </highlightSyntax>
DERIVED
別名「Using subqueries in the FROM clause」とも呼ばれる。読んで字のごとく、FROM句においてサブクエリを利用した場合にDRIVEDとなる。 <highlightSyntax language="mysql"> mysql> EXPLAIN SELECT * FROM Country, (SELECT * FROM City WHERE Population > 1000000) AS C1 WHERE Country.Code = C1.CountryCode; +----+-------------+------------+--------+---------------+---------+---------+----------------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+--------+---------------+---------+---------+----------------+------+-------------+ | 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 237 | | | 1 | PRIMARY | Country | eq_ref | PRIMARY | PRIMARY | 3 | C1.CountryCode | 1 | | | 2 | DERIVED | City | ALL | NULL | NULL | NULL | NULL | 4079 | Using where | +----+-------------+------------+--------+---------------+---------+---------+----------------+------+-------------+ 3 rows in set (0.00 sec) </highlightSyntax> DERIVEDはEXPLAINの結果では後から表示されるが、DERIVEDテーブルを利用するクエリよりも先に実行さることに注意。また、EXPLAINを実行する際にはDERIVEDの部分が実行されて行数の算出が行われる点にも注意すること。(大きなDERIVEDテーブルを利用するクエリを検査したい時には注意が必要である。)
UNION/UNION RESULT
SELECTがUNIONされる対象である場合、select_typeは、
- 最初に行われるSELECTはPRIMARY
- 2番目以降にUNIONされるSELECTはUNION
- UNIONした結果を結合するための処理はUNION RESULT
となる。例えば次のように。 <highlightSyntax language="mysql"> mysql> EXPLAIN SELECT CountryCode FROM CountryLanguage UNION SELECT CountryCode FROM City UNION SELECT Code FROM Country; +----+--------------+-----------------+-------+---------------+---------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+--------------+-----------------+-------+---------------+---------+---------+------+------+-------------+ | 1 | PRIMARY | CountryLanguage | index | NULL | PRIMARY | 33 | NULL | 984 | Using index | | 2 | UNION | City | ALL | NULL | NULL | NULL | NULL | 4079 | | | 3 | UNION | Country | index | NULL | PRIMARY | 3 | NULL | 239 | Using index | | NULL | UNION RESULT | <union1,2,3> | ALL | NULL | NULL | NULL | NULL | NULL | | +----+--------------+-----------------+-------+---------------+---------+---------+------+------+-------------+ 4 rows in set (0.01 sec) </highlightSyntax>
DEPENDENT UNION
DEPENDENT UNIONは、SELECTがUNIONの一部でなおかつ2番目以降のSELECTであり、なおかつサブクエリで用いられている場合に用いられるselect_typeである。 <highlightSyntax language="mysql"> mysql> EXPLAIN SELECT * FROM Country WHERE Code IN (SELECT CountryCode FROM CountryLanguage UNION SELECT CountryCode FROM City); +----+--------------------+-----------------+------+---------------+---------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+--------------------+-----------------+------+---------------+---------+---------+------+------+-------------+ | 1 | PRIMARY | Country | ALL | NULL | NULL | NULL | NULL | 239 | Using where | | 2 | DEPENDENT SUBQUERY | CountryLanguage | ref | PRIMARY | PRIMARY | 3 | func | 9 | Using index | | 3 | DEPENDENT UNION | City | ALL | NULL | NULL | NULL | NULL | 4079 | Using where | | NULL | UNION RESULT | <union2,3> | ALL | NULL | NULL | NULL | NULL | NULL | | +----+--------------------+-----------------+------+---------------+---------+---------+------+------+-------------+ 4 rows in set (0.00 sec) </highlightSyntax>
UNCACHEABLE UNION
UNCACHEABLE SUBQUERYがUNIONになっている場合、2番目以降のUNIONがUNCACHEABLE UNIONとなる。言うまでもなくこのようなクエリは非常に遅い。 <highlightSyntax language="mysql"> mysql> EXPLAIN SELECT Name FROM Country WHERE Code =
-> (SELECT CountryCode FROM City WHERE ID = RAND() -> UNION SELECT CountryCode FROM CountryLanguage WHERE Percentage > RAND() -> ORDER BY CountryCode LIMIT 1);
+----+----------------------+-----------------+-------+---------------+-------------+---------+------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+----------------------+-----------------+-------+---------------+-------------+---------+------+------+--------------------------+ | 1 | PRIMARY | Country | ALL | NULL | NULL | NULL | NULL | 239 | Using where | | 2 | UNCACHEABLE SUBQUERY | City | index | NULL | CountryCode | 3 | NULL | 4217 | Using where; Using index | | 3 | UNCACHEABLE UNION | CountryLanguage | ALL | NULL | NULL | NULL | NULL | 984 | Using where | | NULL | UNION RESULT | <union2,3> | ALL | NULL | NULL | NULL | NULL | NULL | | +----+----------------------+-----------------+-------+---------------+-------------+---------+------+------+--------------------------+ 4 rows in set (0.01 sec) </highlightSyntax>