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总是错误的,还是在构造查询计划时无法将该优化应用于查询?