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;
  1. 走bcd联合索引,扫描叶子节点,每个数据根据主键回表查找(有几个数据回表几次),由于是有序的所以无需再排序

  2. 全表扫描,加载到内存后根据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列的值转为数字,然后再进行比较(没法走索引,因为走的话得改索引)

posted @ 2023-01-05 19:20  antidogmatist  阅读(281)  评论(0编辑  收藏  举报