本文主要是为了验证何种情况下索引会失效,建表使用了innoDB存储引擎 以下是一些索引失效传言,和本人验证结果,基于5.6的版本
- “索引列不能出现null值”,不准确,可能会全表扫描,可能会走索引,看优化器怎么衡量查询的代价
- “模糊查询,只有左匹配才能走索引”,对
- “用了or的查询,必须or两边的条件都满足最左匹配才能走索引”,对
- “隐式转换会引起索引失效”,对
- “!= 不走索引”,不知道,我在主键和非主键索引上验证了都是不走的
另外字段列值允许为null的情况下,查询时有些坑要注意:
- count(*)与count(具体列名)的区别:前者会将null值统计在内,后者不会,取舍要取决于null的业务含义
- sum(具体字段)=null的情况:当查询的结果集为空时,sum的结果为null
- count(1) 和 count(具体列) 是等效的,结果一致
总的来说,查询是否走索引,最终看的是mysql优化器的判断,网上很多“索引失效规律”都是有前提的
建表细节:
CREATE TABLE `t_innodb` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '是否为空对命中索引有啥影响',
`age` int(11) DEFAULT NULL,
`sex` tinyint(1) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`) USING BTREE,
KEY `idx_age_sex` (`age`,`sex`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
show variables like '%basedir%'
SELECT VERSION()
EXPLAIN select * from t_innodb where age = 11
EXPLAIN select age from t_innodb where age > 11 and age <44
EXPLAIN select * from t_innodb where age != 22
select * from t_innodb where age = null
EXPLAIN select * from t_innodb where age is null
EXPLAIN select * from t_innodb where name = '22'
EXPLAIN select * from t_innodb where name = 22
EXPLAIN select name from t_innodb where name != '22'
EXPLAIN select * from t_innodb where name != '22'
EXPLAIN select * from t_innodb where name like '22'
EXPLAIN select * from t_innodb where name like '22%'
EXPLAIN select * from t_innodb where name like '%22'
EXPLAIN select * from t_innodb where name is null
EXPLAIN select name from t_innodb where name is not null
EXPLAIN select * from t_innodb where age = 1 or age = 22
EXPLAIN select * from t_innodb where age = 1 or (age = 2 and sex = 22)
EXPLAIN select * from t_innodb where age = 1 and sex != 22
EXPLAIN select * from t_innodb where age = 11 and sex != 22
SELECT count(name) from t_innodb
SELECT count(*) from t_innodb
SELECT * from t_innodb where name != 'zk'
SELECT * from t_innodb where name != 'zk' or ISNULL(name)
SELECT sum(age) from t_innodb where id = 10
SELECT sum(age) from t_innodb
select 1 + null
select SQL_NO_CACHE * from t_innodb where name != 'zk' or ISNULL(name)
举个栗子说明为啥是否走索引
|