MySQL索引失效的情况有很多,下面主要介绍数据隐式转换导致索引失效。
这一点在我们平常书写SQL语句的时候可能是最容易忽略的但是又是经常容易犯的错误。
开门见山,下面我们看一下官方文档描述。
NULL
时,比较的结果也是NULL
,特殊的情况是使用<=>
对两个NULL
做比较时会返回1
,这两种情况都不需要做类型转换TIMESTAMP
或DATETIME
,并且另外一个参数是常量,常量会被转换为timestamp
decimal
类型,如果另外一个参数是decimal
或者整数,会将整数转换为decimal
后进行比较,如果另外一个参数是浮点数,则会把decimal
转换为浮点数进行比较准备以下字段的表,并且为num1建立索引。
- CREATE TABLE `type` (
- `id` bigint(20) NOT NULL,
- `name` varchar(255) DEFAULT NULL,
- `num1` varchar(255) DEFAULT NULL,
- `num2` int(11) DEFAULT NULL,
- PRIMARY KEY (`id`),
- KEY `index_num1` (`num1`) USING BTREE
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
- 复制代码
在数据库中插入以下数据
方式一
- SELECT * FROM type WHERE num1 = 1000
- 复制代码
注意:这是num1是varchar类型,而查询的时候给的where条件是1000的整形。
这时查询得到的数据时包含其他脏数据的。
explain分析查询语句,结果走了全表扫描。
方式二
在对num1字段的where语句拼接上单引号后查询的结果和我们预期一样。
- SELECT * FROM type WHERE num1 = '1000'
- 复制代码
explain分析查询语句,结果走了索引,索引生效了。
那么这个字符串隐式转换的规则是什么呢?为什么num1='1000a'
、'01000'
和'1000'
这三种情形都能匹配上呢?查阅相关资料发现规则如下:
0
。如'abc'
、'a123bc'
、'abc123'
都会转化为0
;'123abc'
会转换为123
,'012abc'
会转换为012
也就是12
,'5.3a66b78c'
会转换为5.3
,其他同理。验证结果
0
,以数字开头的字符串会截取从第一个字符到第一个非数字内容为止的值为转化结果。所以,我们在写 SQL 时一定要养成良好的习惯,查询的字段是什么类型,等号右边的条件就写成对应的类型。特别当查询的字段是字符串时,等号右边的条件一定要用引号引起来标明这是一个字符串,否则会造成索引失效触发全表扫描。