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>

個人用ツール