MySQL 5.5.28。我有两个表Person,Message后者有一个外键。每个表都有id一个主键列,并且该Person表还有一个personId(唯一)索引的列。
下面的查询应该利用personId键索引,但 MySQLMessage出于某种原因需要扫描整个表:
mysql> 解释 SELECT `m`.*
-> 从
-> `消息`作为`m`
-> 左连接
-> `Person` AS `p` ON (`m`.`person` = `p`.`id`)
-> 在哪里
-> 'M002649397' 为空或
-> `p`.`personId` = 'M002649397';
+----+-------------+--------+--------+------------- --+---------+---------+----------------+--------+- ------------+
| 编号 | 选择类型 | 表| 类型 | 可能的键 | 关键 | key_len | 参考 | 行 | 额外 |
+----+-------------+--------+--------+------------- --+---------+---------+----------------+--------+- ------------+
| 1 | 简单 | 米 | 全部 | 空 | 空 | 空 | 空 | 273220 | |
| 1 | 简单 | p | eq_ref | 初级 | 初级 | 8 | pcom.m.人 | 1 | 使用位置 |
+----+-------------+--------+--------+------------- --+---------+---------+----------------+--------+- ------------+
2 行(0.00 秒)
但是当我注释掉'M002649397' IS NULL OR子句(对结果没有影响)时,查询突然变得更有效率:
mysql> 解释 SELECT `m`.*
-> 从
-> `消息`作为`m`
-> 左连接
-> `Person` AS `p` ON (`m`.`person` = `p`.`id`)
-> 在哪里
-> -- 'M002649397' 为空或
-> `p`.`personId` = 'M002649397';
+----+-------------+--------+-------+-------------- ------+--------+---------+--------+---- --+--------------+
| 编号 | 选择类型 | 表| 类型 | 可能的键 | 关键 | key_len | 参考 | 行 | 额外 |
+----+-------------+--------+-------+-------------- ------+--------+---------+--------+---- --+--------------+
| 1 | 简单 | p | 常量 | PRIMARY,personId | 人名 | 第767章 常量 | 1 | 使用索引 |
| 1 | 简单 | 米 | 参考 | FK9C2397E7A0F6ED11 | FK9C2397E7A0F6ED11 | 9 | 常量 | 3 | 使用位置 |
+----+-------------+--------+-------+-------------- ------+--------+---------+--------+---- --+--------------+
2 行(0.01 秒)
我的问题是:为什么 MySQL 不够聪明,无法意识到这'M002649397' IS NULL总是错误的,优化它,省去不必要地扫描大表中的每一行?
换句话说,MySQL 优化器是否不知道它'M002649397' IS NULL总是错误的,或者它在构建其查询计划时未能将该优化应用于查询?