MySQL查詢執行計劃的警告信息辨析一例

實例1 :引入實例

Step 1: 創建表

CREATE TABLE `t1` ( 
  `id` SMALLINT(6) NOT NULL DEFAULT '99', 
  `txt` TEXT, 
  PRIMARY KEY (`id`) 
) ENGINE=INNODB DEFAULT CHARSET=utf8; 
INSERT INTO t1 (id,txt) VALUES (1,'a'), (2,'b'), (3,'c'); 
DROP TABLE IF EXISTS t2; 
CREATE TABLE `t2` ( 
  `id` SMALLINT(6) NOT NULL DEFAULT '99', 
  `txt` TEXT, 
  PRIMARY KEY (`id`) 
) ENGINE=INNODB DEFAULT CHARSET=utf8; 
INSERT INTO t2 (id,txt) VALUES (1,'x'), (2,'y'), (3,'x');

 

Step 2: 顯示執行計劃,並獲取警告信息

mysql> EXPLAIN EXTENDED SELECT t1.id FROM t1,t2 WHERE t2.id=3 and t1.id=2;

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

| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |

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

| 1 | SIMPLE | t1 | NULL | const | PRIMARY | PRIMARY | 2 | const | 1 | 100.00 | Using index |

| 1 | SIMPLE | t2 | NULL | const | PRIMARY | PRIMARY | 2 | const | 1 | 100.00 | Using index |

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

2 rows in set, 2 warnings (0.00 sec)


mysql> show warnings;

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

| Level | Code | Message |

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

| Warning | 1681 | 'EXTENDED' is deprecated and will be removed in a future release. |

| Note | 1003 | /* select#1 */ select '2' AS `id` from `d2`.`t1` join `d2`.`t2` where 1 |

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

2 rows in set (0.00 sec)


問題:

Q1:爲什麼警告信息中的SQL語句不等同於原始的SQL語句?

Q2:爲什麼警告信息中顯示的WHERE子句內容, 是“where 1” ?


原因探索:

A1:MySQL在手冊8.8.3節中描述如下(refman-5.7-en.html-chapter/optimization.html):

Because the statement displayed by SHOW WARNINGS may contain special markers to provide information about query rewriting or optimizer actions, the statement is not necessarily valid SQL and is not intended to be executed. The output may also include rows with Message values that provide additional non-SQL explanatory notes about actions taken by the optimizer.


這表明:

1)查詢執行計劃的警告信息,只是起提示作用的,不等同於原始SQL,也不等同於優化後的被執行器執行的SQL


A2:“where 1”,產生於等式表達式,看如下實例:

實例2:等式與不等式的查詢執行計劃實例

Case 0:

mysql> EXPLAIN EXTENDED SELECT t2.id FROM t2 WHERE t2.id=3;
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | t2    | NULL       | const | PRIMARY       | PRIMARY | 2       | const |    1 |   100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
1 row in set, 2 warnings (0.00 sec)

mysql> show warnings;
+---------+------+-------------------------------------------------------------------+
| Level   | Code | Message                                                           |
+---------+------+-------------------------------------------------------------------+
| Warning | 1681 | 'EXTENDED' is deprecated and will be removed in a future release. |
| Note    | 1003 | /* select#1 */ select '3' AS `id` from `d2`.`t2` where 1          |
+---------+------+-------------------------------------------------------------------+
2 rows in set (0.00 sec)


 

Case 1:

--------

mysql> EXPLAIN EXTENDED SELECT t1.id FROM t1,t2 WHERE t2.id=3 and t1.id=2;
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | t1    | NULL       | const | PRIMARY       | PRIMARY | 2       | const |    1 |   100.00 | Using index |
|  1 | SIMPLE      | t2    | NULL       | const | PRIMARY       | PRIMARY | 2       | const |    1 |   100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
2 rows in set, 2 warnings (10.87 sec)

mysql> show warnings;
+---------+------+-----------------------------------------------------------------------------+
| Level   | Code | Message                                                                     |
+---------+------+-----------------------------------------------------------------------------+
| Warning | 1681 | 'EXTENDED' is deprecated and will be removed in a future release.           |
| Note    | 1003 | /* select#1 */ select '2' AS `id` from `test`.`t1` join `test`.`t2` where 1 |
+---------+------+-----------------------------------------------------------------------------+
2 rows in set (0.00 sec)


Case 2:

mysql> EXPLAIN EXTENDED SELECT t1.id FROM t1,t2 WHERE t2.id=3 and t1.id>2;
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+--------------------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra                    |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+--------------------------+
|  1 | SIMPLE      | t2    | NULL       | const | PRIMARY       | PRIMARY | 2       | const |    1 |   100.00 | Using index              |
|  1 | SIMPLE      | t1    | NULL       | range | PRIMARY       | PRIMARY | 2       | NULL  |    1 |   100.00 | Using where; Using index |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+--------------------------+
2 rows in set, 2 warnings (0.00 sec)

mysql> show warnings;
+---------+------+-----------------------------------------------------------------------------------------------------------------+
| Level   | Code | Message                                                                                                         |
+---------+------+-----------------------------------------------------------------------------------------------------------------+
| Warning | 1681 | 'EXTENDED' is deprecated and will be removed in a future release.                                               |
| Note    | 1003 | /* select#1 */ select `test`.`t1`.`id` AS `id` from `test`.`t1` join `test`.`t2` where ((`test`.`t1`.`id` > 2)) |
+---------+------+-----------------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)


 

Case 3:

mysql> EXPLAIN EXTENDED SELECT t1.id FROM t1,t2 WHERE t2.id=3 or t1.id>2;
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+----------------------------------------
-------------------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra
                         |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+----------------------------------------
-------------------------+
|  1 | SIMPLE      | t1    | NULL       | index | PRIMARY       | PRIMARY | 2       | NULL |    3 |   100.00 | Using index
                         |
|  1 | SIMPLE      | t2    | NULL       | index | PRIMARY       | PRIMARY | 2       | NULL |    3 |   100.00 | Using where; Using index; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+----------------------------------------
-------------------------+
2 rows in set, 2 warnings (0.00 sec)

 

mysql> show warnings;
+---------+------+------------------------------------------------------------------------------------------------------------------------------------
-------+
| Level   | Code | Message
       |
+---------+------+------------------------------------------------------------------------------------------------------------------------------------
-------+
| Warning | 1681 | 'EXTENDED' is deprecated and will be removed in a future release.
       |
| Note    | 1003 | /* select#1 */ select `test`.`t1`.`id` AS `id` from `test`.`t1` join `test`.`t2` where ((`test`.`t2`.`id` = 3) or (`test`.`t1`.`id` > 2)) |
+---------+------+------------------------------------------------------------------------------------------------------------------------------------
-------+
2 rows in set (0.00 sec)

 


Case 4:

mysql> EXPLAIN EXTENDED SELECT t1.id FROM t1,t2 WHERE t2.id=3 or t1.id=2;
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+----------------------------------------
-------------------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra
                         |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+----------------------------------------
-------------------------+
|  1 | SIMPLE      | t1    | NULL       | index | PRIMARY       | PRIMARY | 2       | NULL |    3 |   100.00 | Using index
                         |
|  1 | SIMPLE      | t2    | NULL       | index | PRIMARY       | PRIMARY | 2       | NULL |    3 |   100.00 | Using where; Using index; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+----------------------------------------
-------------------------+
2 rows in set, 2 warnings (0.00 sec)

 

mysql> show warnings;
+---------+------+------------------------------------------------------------------------------------------------------------------------------------
-------+
| Level   | Code | Message
       |
+---------+------+------------------------------------------------------------------------------------------------------------------------------------
-------+
| Warning | 1681 | 'EXTENDED' is deprecated and will be removed in a future release.
       |
| Note    | 1003 | /* select#1 */ select `test`.`t1`.`id` AS `id` from `test`.`t1` join `test`.`t2` where ((`test`.`t2`.`id` = 3) or (`test`.`t1`.`id` = 2)) |
+---------+------+------------------------------------------------------------------------------------------------------------------------------------
-------+
2 rows in set (0.00 sec)


Case 5:

mysql> EXPLAIN EXTENDED SELECT t1.id FROM t1,t2 WHERE t1.id<2;
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+----------------------------------------
------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra
            |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+----------------------------------------
------------+
|  1 | SIMPLE      | t1    | NULL       | range | PRIMARY       | PRIMARY | 2       | NULL |    1 |   100.00 | Using where; Using index
            |
|  1 | SIMPLE      | t2    | NULL       | index | NULL          | PRIMARY | 2       | NULL |    3 |   100.00 | Using index; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+----------------------------------------
------------+
2 rows in set, 2 warnings (0.00 sec)

mysql> show warnings;
+---------+------+---------------------------------------------------------------------------------------------------------------+
| Level   | Code | Message                                                                                                       |
+---------+------+---------------------------------------------------------------------------------------------------------------+
| Warning | 1681 | 'EXTENDED' is deprecated and will be removed in a future release.                                             |
| Note    | 1003 | /* select#1 */ select `test`.`t1`.`id` AS `id` from `test`.`t1` join `test`.`t2` where (`test`.`t1`.`id` < 2) |
+---------+------+---------------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)


總結:

case   | format   | output of WARNINGS

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

case 0 | equality | where 1

Case 1 | equality AND equality | where 1

Case 2 | equality AND inequality | (`test`.`t1`.`id`> 2)

Case 3 | equality OR inequality | ((`test`.`t2`.`id` = 3) or (`test`.`t1`.`id` > 2))

Case 4 | equality OR equality | ((`test`.`t2`.`id` =3) or (`test`.`t1`.`id` = 2))

Case 5 | inequality | (`test`.`t1`.`id` < 2)

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



從總結中,我們可以看出,當有等式且用AND操作的時候,表的訪問類型是const,則優化器找到與等式匹配的元組,這樣等式變爲“3=3”(case 0),進一步可以優化爲TRUE,所以WHERE子句變爲“1”表示TRUE。


實例3:與以上結論相應的實例(改造case 0的條件)

mysql> EXPLAIN EXTENDED SELECT t2.id FROM t2 WHERE t2.id=30;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                          |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------+
|  1 | SIMPLE      | NULL  | NULL       | NULL | NULL          | NULL | NULL    | NULL | NULL |     NULL | no matching row in const table |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------+
1 row in set, 2 warnings (0.00 sec)

mysql> show warnings;

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

| Level | Code | Message |

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

| Warning | 1681 | 'EXTENDED' is deprecated and will be removed in a future release. |

| Note | 1003 | /* select#1 */ select NULL AS `id` from `d2`.`t2` where multiple equal(30, NULL) |

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




這表明,A2對於問題2的回答,是說明了一種特殊情況。需要注意此特殊情況成立的條件。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章