MySQL:为什么'FOO'没有被优化掉?

Arc*_*hie 6 mysql

MySQL 5.5.28.我有两个表Person,Message后者有一个外键给前者.每个表都有id主键列,Person表中还有一个personId(唯一)索引的列.

下面的查询应该利用personId密钥索引,但是MySQL需要扫描整个Message表,原因如下:

mysql> EXPLAIN SELECT `m`.*
    -> FROM
    ->   `Message` AS `m`
    -> LEFT JOIN
    ->   `Person` AS `p` ON (`m`.`person` = `p`.`id`)
    -> WHERE
    ->   'M002649397' IS NULL OR
    ->   `p`.`personId` = 'M002649397';
+----+-------------+-------+--------+---------------+---------+---------+----------------+--------+-------------+
| id | select_type | table | type   | possible_keys | key     | key_len | ref            | rows   | Extra       |
+----+-------------+-------+--------+---------------+---------+---------+----------------+--------+-------------+
|  1 | SIMPLE      | m     | ALL    | NULL          | NULL    | NULL    | NULL           | 273220 |             |
|  1 | SIMPLE      | p     | eq_ref | PRIMARY       | PRIMARY | 8       | pcom.m.person  |      1 | Using where |
+----+-------------+-------+--------+---------------+---------+---------+----------------+--------+-------------+
2 rows in set (0.00 sec)

但是当我注释掉该'M002649397' IS NULL OR子句(对结果没有影响)时,查询突然变得更有效:

mysql> EXPLAIN SELECT `m`.*
    -> FROM
    ->   `Message` AS `m`
    -> LEFT JOIN
    ->   `Person` AS `p` ON (`m`.`person` = `p`.`id`)
    -> WHERE
    -> --  'M002649397' IS NULL OR
    ->   `p`.`personId` = 'M002649397';
+----+-------------+-------+-------+--------------------+--------------------+---------+-------+------+-------------+
| id | select_type | table | type  | possible_keys      | key                | key_len | ref   | rows | Extra       |
+----+-------------+-------+-------+--------------------+--------------------+---------+-------+------+-------------+
|  1 | SIMPLE      | p     | const | PRIMARY,personId   | personId           | 767     | const |    1 | Using index |
|  1 | SIMPLE      | m     | ref   | FK9C2397E7A0F6ED11 | FK9C2397E7A0F6ED11 | 9       | const |    3 | Using where |
+----+-------------+-------+-------+--------------------+--------------------+---------+-------+------+-------------+
2 rows in set (0.01 sec)

我的问题是:为什么MySQL不够聪明才能意识到'M002649397' IS NULL总是错误的,优化它,并且不必不必要地扫描巨大的表中的每一行?

换句话说,MySQL优化器不知道它'M002649397' IS NULL总是错误的,还是在构造查询计划时无法将该优化应用于查询?

Gor*_*off 1

实际上,更有趣的是,文档说 MySQL 足够聪明,可以做到这一点(请参阅此处)。

\n\n

这似乎属于标题“8.2.1.2.消除 \xe2\x80\x9cDead\xe2\x80\x9d 代码”。

\n\n

我想原因是开发人员在编写代码时没有考虑“is not null”这样的表达式。该文档给出了许多基于恒定传播(x1 = 2 and x2 = x1变成x1 = 2 and x2 = 2)的示例。 is null可能确实会出现在这种情况下。

\n