MySQL复合索引的最左匹配原则

聊聊MySQL复合索引的最左匹配原则:从一个简单例子说起

在这里插入图片描述

今天想跟你们聊聊MySQL里一个挺有意思的话题——复合索引的最左匹配原则。说实话,我刚接触数据库的时候,看到索引这个东西脑袋就有点晕,后来慢慢踩了点坑,才发现这玩意儿其实没那么神秘,反而有点像生活里找东西的逻辑。今天就拿个小例子,带你们看看这东西到底怎么回事,顺便分享下我的理解和心得。

先搭个简单场景

假设我们有个用户信息表,叫user_info,里面存了些基本信息:ID、姓名、年龄、城市,还有创建时间。建表语句长这样:

CREATE TABLE user_info (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50),
    age INT,
    city VARCHAR(50),
    create_time DATETIME
);

为了方便查询,我给nameagecity这三列加了个复合索引:

ALTER TABLE user_info ADD INDEX idx_name_age_city (name, age, city);

然后往里塞了点数据,比如:

INSERT INTO user_info (name, age, city, create_time) VALUES
('张三', 25, '北京', '2023-01-01 10:00:00'),
('张三', 30, '上海', '2023-01-02 10:00:00'),
('李四', 25, '广州', '2023-01-03 10:00:00'),
('王五', 35, '深圳', '2023-01-04 10:00:00'),
('赵六', 28, '北京', '2023-01-05 10:00:00');

数据不多,但够我们玩一玩了。接下来,我想查查这些数据在不同条件下的查询计划,看看这个复合索引到底咋工作的。

最左匹配原则是个啥?

复合索引听起来高大上,其实你可以把它想象成一本书的目录。你按nameagecity的顺序建了索引,MySQL就会老老实实按照这个顺序去排。查的时候,它就得从最左边(name)开始匹配,不能跳着来。这就是所谓的最左匹配原则。

我第一次听说这个的时候,感觉挺抽象,后来拿生活举个例子就好懂了。假设你在找一本书,书架是按作者名、出版年、书名排序的。你要是直接说“给我找本2020年的书”,那就得把书架翻个遍,因为你没说作者名,顺序从头乱了。可如果你说“给我找张三写的书”,那就能先锁定张三的区域,再往下细找。

好了,废话不多说,咱们直接上EXPLAIN,看看查询计划咋样。

完全匹配:教科书式的完美

先来个最标准的查询:

EXPLAIN SELECT * FROM user_info 
WHERE name = '张三' AND age = 25 AND city = '北京';

结果呢?MySQL告诉我:type: refkey: idx_name_age_cityref: const,const,const。这说明啥?索引用上了,而且用得贼漂亮!因为我老老实实按nameagecity的顺序给了条件,MySQL直接通过索引定位到数据,效率杠杠的。就像我在书架上直接找到“张三-25岁-北京”这本书,so easy!

跳过最左列:索引直接废了

再试个不按套路来的:

EXPLAIN SELECT * FROM user_info 
WHERE age = 25 AND city = '北京';

结果咋样?type: ALLkey: nullref: null。哎哟,这不就全表扫描了吗?索引完全没用上!为啥?因为我没给name,相当于跳过了目录的第一页,MySQL只好傻乎乎地从头扫到尾。这让我想起有次找东西,直接问“我要个红色的”,结果翻遍了家才找到——没个开头线索,太费劲了。

缺了中间一列:还能凑合用

那如果我只跳过中间的age呢?

EXPLAIN SELECT * FROM user_info 
WHERE name = '张三' AND city = '北京';

这次结果是:type: refkey: idx_name_age_cityref: const。嘿,有点意思!索引还是用上了,虽然没用全。MySQL先通过name锁定范围,然后在这些范围内再过滤city。这说明啥?最左匹配原则不是说非得用全所有列,而是得从左边开始,中间断了还能凑合用点,但肯定不如全匹配效率高。

用OR的时候:彻底懵圈

再来个带OR的:

EXPLAIN SELECT * FROM user_info 
WHERE name = '张三' OR city = '北京';

结果又是:type: ALLkey: nullref: null。全表扫描又来了!为啥?因为OR把条件拆开了,MySQL觉得每个条件都得单独查一遍,索引就不好使了。就像我妈让我找“张三的书或者红色的书”,我只能两头跑,目录帮不上啥忙。

再试个更乱的:

EXPLAIN SELECT * FROM user_info 
WHERE name = '张三' OR age = 25 OR city = '北京';

一样,全表扫描。MySQL看到这么多OR,估计都头大了,直接放弃索引,走最笨的路。

我的小总结

折腾了这一圈,我算是把最左匹配原则摸透了点。简单来说:

  1. 从左开始:复合索引得从最左列用起,跳过了开头就废了。
  2. 中间断裂没事:只要开头对了,后面跳过几列还能用点索引。
  3. OR是大杀器:一旦条件里混了OR,索引基本就歇菜了,除非你能优化成别的形式。

这让我想起之前写代码踩的坑。有次我给个查询加了个复合索引,结果性能还是烂,后来发现条件顺序没对上,白忙活一场。从那以后,我每次建索引前都会先想想查询习惯,省得费力不讨好。

你可能感兴趣的:(MySQL,mysql,android,数据库)