EXPLAIN EXTENDEDはどのような興味深いことを教えてくれますか?

ほとんどのMySQL開発者はEXPLAINチームに精通していますが、MySQL 4.1に登場したEXPLAIN EXTENDEDコマンドを知っている人は非常に少なく、その使用方法もあまり知りません。



EXPLAIN EXTENDEDは、MySQLオプティマイザーがクエリで正確に実行することを示すことができます。 開発者にとって、彼によって書かれたリクエストが実際にサーバーによって実行されるリクエストとどれだけ異なるかは明らかではないかもしれません。 このプロセスはクエリ書き換えメカニズムと呼ばれ、優れたSQLオプティマイザーの一部です。 EXPLAIN EXTENDEDコマンドは、書き換えられたSQLクエリなど、EXPLAINコマンドの出力に追加の警告を追加します。





最初に、3つの空のテーブルを作成しましょう。 ここで、テーブルが空であることが重要です。なぜなら、 MySQLオプティマイザーは、複数の行を含むテーブルよりも、空のテーブル(特に1行のみを含むテーブル)で特に機能します。



mysql> CREATE TABLE j1 (c1 int);

Query OK, 0 rows affected (0.16 sec)

CREATE TABLE j2 (c1 int);

Query OK, 0 rows affected (0.11 sec)

mysql> CREATE TABLE j3 (c1 int);

Query OK, 0 rows affected (0.10 sec)








mysql> EXPLAIN extended SELECT j1.c1 FROM j1, j2, j3 WHERE j1.c1 = j2.c1 AND j3.c1 = j1.c1;

+----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+

| id | select_type | TABLE | type | possible_keys | KEY | key_len | ref | rows | Extra

+----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+

| 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Impossible WHERE noticed after reading const TABLES

+----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+

1 row IN SET, 1 warning (0.04 sec)

mysql> SHOW warnings;

+-------+------+-------------------------------------------------------------------------------+

| Level | Code | Message

+-------+------+-------------------------------------------------------------------------------+

| Note | 1003 | SELECT '0' AS `c1` FROM `test`.`j1` JOIN `test`.`j2` JOIN `test`.`j3` WHERE 0

+-------+------+-------------------------------------------------------------------------------+

1 row IN SET (0.00 sec)








EXPLAINコマンドの出力には、奇妙なことに気付くかもしれません。 まず、テーブルはリストされません。 Extra列を見ると、MySQLが「const」という単語に言及していることがわかります。 テーブル 'const'は、0行または1行を含むテーブル、または、WHEREのパラメーターを完全に満たすPRIMARYまたはUNIQUEキーのすべての部分のテーブルです。 タイプ 'const'のテーブルに行が含まれておらず、OUTER JOINで使用されていない場合、MySQLはすぐに空の結果を返します。 クエリを満たすテーブルの共通部分は存在できません。 MySQLは、WHEREパラメーターの代わりにWHERE-WHERE 0を追加することでこれを実現します。



各テーブルに1つ追加するとどうなるか見てみましょう。

mysql> INSERT INTO j1 VALUES (1); INSERT INTO j2 SELECT * FROM j1; INSERT INTO j3 SELECT * FROM j2;

Query OK, 1 row affected (0.00 sec)

mysql> EXPLAIN extended SELECT j1.c1 FROM j1, j2, j3 WHERE j1.c1 = j2.c1 AND j3.c1 = j1.c1;

+----+-------------+-------+--------+---------------+------+---------+------+------+-------+

| id | select_type | TABLE | type | possible_keys | KEY | key_len | ref | rows | Extra

+----+-------------+-------+--------+---------------+------+---------+------+------+-------+

| 1 | SIMPLE | j1 | system | NULL | NULL | NULL | NULL | 1 |

| 1 | SIMPLE | j2 | system | NULL | NULL | NULL | NULL | 1 |

| 1 | SIMPLE | j3 | system | NULL | NULL | NULL | NULL | 1 |

+----+-------------+-------+--------+---------------+------+---------+------+------+-------+

3 rows IN SET, 1 warning (0.00 sec)

mysql> SHOW warnings;

+-------+------+-------------------------------------------------------------------------------+

| Level | Code | Message

+-------+------+-------------------------------------------------------------------------------+

| Note | 1003 | SELECT '1' AS `c1` FROM `test`.`j1` JOIN `test`.`j2` JOIN `test`.`j3` WHERE 1

+-------+------+-------------------------------------------------------------------------------+

1 row IN SET (0.00 sec)








ご覧のとおり、EXPLAIN結果にテーブルが表示されていますが、テーブルタイプが「システム」として指定されていることに注意してください。 このタイプのテーブルは、1行のみを含む「const」タイプのテーブルの一種です。 このテーブルの内容は、クエリの開始前に完全に読み取られるため、MySQLは、実行プランが形成される前であっても、テーブルの値を定数として指定されたパラメータと比較できます。 さらに、MySQLはWHEREのすべてのパラメーターをWHERE 1に置き換えました。 クエリで使用されるすべてのテーブルに同じ値が含まれていることを知っています。 そうでない場合は、前のケースと同様に、WHERE 0を追加します。



最後に、テーブルにさらにデータを追加して、クエリをテストしましょう。

mysql> INSERT INTO j1 VALUES (1); INSERT INTO j2 SELECT * FROM j1; INSERT INTO j3 SELECT * FROM j2;

mysql> EXPLAIN extended SELECT j1.c1 FROM j1, j2, j3 WHERE j1.c1 = j2.c1 AND j3.c1 = j1.c1;

+----+-------------+-------+------+---------------+------+---------+------+------+-------------+

| id | select_type | TABLE | type | possible_keys | KEY | key_len | ref | rows | Extra

+----+-------------+-------+------+---------------+------+---------+------+------+-------------+

| 1 | SIMPLE | j1 | ALL | NULL | NULL | NULL | NULL | 2 |

| 1 | SIMPLE | j2 | ALL | NULL | NULL | NULL | NULL | 3 | USING WHERE

| 1 | SIMPLE | j3 | ALL | NULL | NULL | NULL | NULL | 4 | USING WHERE

+----+-------------+-------+------+---------------+------+---------+------+------+-------------+

3 rows IN SET, 1 warning (0.00 sec)

mysql> SHOW warnings;

+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

| Level | Code | Message

+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

| Note | 1003 | SELECT `test`.`j1`.`c1` AS `c1` FROM `test`.`j1` JOIN `test`.`j2` JOIN `test`.`j3` WHERE ((`test`.`j2`.`c1` = `test`.`j1`.`c1`) AND (`test`.`j3`.`c1` = `test`.`j1`.`c1`))

+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

1 row IN SET (0.00 sec)








type列に値ALLが表示されるようになりました。これは、MySQLがテーブル全体を読み取ることを意味します。 これは、テーブルにインデックスがないためです。



以前に注意する必要のある他の興味深いことがあります。おそらく、コンマでリストされたすべてのテーブルがMySQL JOINオプティマイザーによって自動的に結合されることにすでに気付いているでしょう。 したがって、より速く、より最適に機能するものについての論争-コンマまたは結合でテーブルを列挙する-は無意味になります それは本質的に同じことです。



そして最後の1つ。 EXPLAIN EXTENDEDが、MERGEアルゴリズムを使用するビューを使用する場合のMySQLオプティマイザーの動作について、どのような情報を提供しているか見てみましょう。

mysql> CREATE VIEW v1 AS SELECT * FROM j1;

Query OK, 0 rows affected (0.10 sec)

mysql> EXPLAIN extended SELECT * FROM v1 WHERE c1=1;

+----+-------------+-------+------+---------------+------+---------+------+------+-------------+

| id | select_type | TABLE | type | possible_keys | KEY | key_len | ref | rows | Extra

+----+-------------+-------+------+---------------+------+---------+------+------+-------------+

| 1 | SIMPLE | j1 | ALL | NULL | NULL | NULL | NULL | 2 | USING WHERE

+----+-------------+-------+------+---------------+------+---------+------+------+-------------+

1 row IN SET, 1 warning (0.00 sec)

mysql> SHOW warnings;

+-------+------+-------------------------------------------------------------------------------+

| Level | Code | Message

+-------+------+-------------------------------------------------------------------------------+

| Note | 1003 | SELECT `test`.`j1`.`c1` AS `c1` FROM `test`.`j1` WHERE (`test`.`j1`.`c1` = 1)

+-------+------+-------------------------------------------------------------------------------+

1 row IN SET (0.00 sec)








最も興味深く、重要なものは、WHEREに書かれています。 ご覧のとおり、ビューを作成するときに説明したリクエストは、アクセスするリクエストのWHEREで指定したパラメーターに従って書き換えられました。



翻訳者から



記事に対するコメントからの興味深い事実:




All Articles