Skip to content

最左前缀法则

联合索引,要遵守最左前缀法则。最左前缀法则指的是查询从索引的最左列开始,并且不跳过索引中的列。如果跳跃某一列,索引将会部分失效(后面的字段索引失效)。

注意点:

  • 索引列的顺序指的是创建索引时指定的顺序
  • 必须包含最左边的索引列,不然失效
  • 最左边的索引列存在就行,不需要管查询语句中的索引列的顺序
  • 跳跃了某一列,该列及之后的索引字段都会失效
  • 如果出现了范围查询,比如大于、小于这种,则右边的列索引失效
    • 解决方法:使用大于等于、小于等于

举例说明

建表语句

CREATE TABLE `tb_user` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(50) NOT NULL COMMENT '用户名',
  `phone` varchar(11) NOT NULL COMMENT '手机号',
  `email` varchar(100) DEFAULT NULL COMMENT '邮箱',
  `profession` varchar(11) DEFAULT NULL COMMENT '专业',
  `age` tinyint unsigned DEFAULT NULL COMMENT '年龄',
  `gender` char(1) DEFAULT NULL COMMENT '性别 , 1: 男, 2: 女',
  `status` char(1) DEFAULT NULL COMMENT '状态',
  `createtime` datetime DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`),
  KEY `idx_user_pro_age_sta` (`profession`,`age`,`status`),
  KEY `idx_user_phone` (`phone`)
);

-- 然后随便插入几条数据即可

测试及截图

符合规则的情况

-- 以下语句都符合最左前缀法则
select * from tb_user where profession='软件工程' and age = 31 and status = '0';
select * from tb_user where profession='软件工程' and age = 31;
select * from tb_user where profession='软件工程';
-- 乱序也能走索引, 同样符合最左前缀法则
select * from tb_user where age = 31 and profession='软件工程';

image-20230906195500680

索引失效的情况

select * from tb_user where age = 31 and status = '0';

image-20230906200202169

部分失效的情况

-- status 部分的索引失效
select * from tb_user where profession='软件工程' and age > 31 and status = '0';

image-20230906201702706

但是修改为大于等于就能用到全部的索引

select * from tb_user where profession='软件工程' and age >= 31 and status = '0';

image-20230906201823520

索引失效的情况

索引列运算

select * from tb_user where substring(phone,10,2) = '15';

数据类型转换

比如,字符串类型的数据查询的时候查询条件不加引号

-- status 数据类型是字符串
select * from tb_user where profession='软件工程' and age = 31 and status = 0;

头部模糊查询

尾部模糊匹配,索引不会失效。

头部模糊匹配,索引失效(前面加百分号)

or 连接

用 or 分割开的条件, 如果 or 条件中的列一侧有索引,一侧没有索引,那么涉及的索引都不会被用到

select * from tb_user where id = 10 or age = 23;
select * from tb_user where age = 23 or id = 10;

image-20230906203519513

select * from tb_user where id = 10 or profession = '软件工程';-- 这个会走索引, 因为两侧都有索引

image-20230906203840043

数据分布影响

MySQL在查询时,会评估使用索引的效率与走全表扫描的效率,如果走全表扫描更快,则放弃索引,走全表扫描。

因为索引是用来索引少量数据的,如果通过索引查询返回大批量的数据,则还不如走全表扫描来的快,此时索引就会失效