MySQL联合索引
eg, 表t中含有abcde五个字段,a为主键,bcd有联合索引
CREATE TABLE `t` (
`a` int primary key,
`b` int,
`c` int,
`d` int,
`e` varchar(20)
) ENGINE=InnoDB;
create index idx_t_bcd on t(b,c,d);
create index idx_t_e on t(e);
为什么遵循最左前缀原则才能利用到索引
结合联合索引的结构,局部有序
范围查找导致索引失效的原因
select * from t where b > 1;
此时走的是全表扫描,why?
因为是select * ,要回表,全表扫描的话无需回表,innodb如果判断回表次数太多,就会选择全表扫描,但是如果需要回表的次数比较少,比如b>6,就可以走索引。
覆盖索引
select a,b,c,d from t where b > 1;
可以走索引,并且using index(覆盖索引),因为索引里面本身就有b字段,无需回表
索引扫描原理
select b from t
可以走bcd索引,因为相比于全表扫描,一页中的数据肯定是没有非聚簇索引叶子节点的页存储的数据多,因此同样的数据量扫描索引的叶子节点遍历的页更少。而且select的字段只要是属于索引的列或主键列都可以走索引,此时并不需要最左前缀原则,因为是全部扫描。
order by导致索引失效
select * from t order by b,c,d;
-
走bcd联合索引,扫描叶子节点,每个数据根据主键回表查找(有几个数据回表几次),由于是有序的所以无需再排序
-
全表扫描,加载到内存后根据bcd进行排序(不需要回表)
此时就会走全表扫描
然而,
select b from t order by b,c,d;
就不需要回表,因此采用走索引的方式
对字符进行操作导致索引失效
数据类型转换
select 'a' = 0; -- 1
select 'b' = 1; -- 0
select 'b' = 0; -- 1
可以发现,在字符和数字进行比较时,MySQL会将字符隐式转换为数字,如上,字符都会被转成0,但是'123'会被转成数字123
select * from t where a = 'a';
相当于
select * from t where a = 0;
而
select * from t where a = '1';
相当于
select * from t where a = 1;
另外一个场景:
select * from t where e = 1
会先将所有e列的值转为数字,然后再进行比较(没法走索引,因为走的话得改索引)