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的回答,是说明了一种特殊情况。需要注意此特殊情况成立的条件。


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