当前位置: 首页 > news >正文

MySQL 中的最左前缀法则

文章目录

    • “最左前缀法则” 是什么?
    • 环境准备
    • 符合最左前缀法则的查询
      • 示例 1:使用最左列查询
      • 示例 2:使用最左两列查询
    • 不符合最左前缀法则的查询
      • 示例 1:跳过最左列
      • 示例 2:范围查询后使用索引列

“最左前缀法则” 是什么?

在 MySQL 中,最左前缀法则是针对复合索引(也称为联合索引)的一个重要规则。复合索引是指在表的多个列上创建的索引。最左前缀法则规定,在使用复合索引进行查询时,MySQL 会从索引的最左边的列开始,依次向右匹配,直到遇到范围查询(如 ><BETWEENLIKE 以通配符开头)等不能使用索引的条件为止。只有符合最左前缀的查询条件才能有效利用复合索引来提高查询效率。

注意:

  • 最左前缀法则规定使用联合索引不能跳过其中的某一列,如果跳过其中某一列,索引将部分失效(该列后面的字段索引失效);
  • 最左前缀法则是要求联合索引最左边的列必须被使用,而不是要求要把查询条件放在 where 语句的最左边,实际上最左前缀法则与查询条件放置的位置没有关系。

MySQL 中的最左前缀法则的原理在于索引是按照索引列的顺序进行排序的,查询时会根据索引的顺序进行搜索。如果查询条件不满足最左前缀法则,那么数据库无法利用索引的有序性,可能需要进行全表扫描,导致查询性能下降。

最左前缀法则是 MySQL 中复合索引使用的重要规则。在设计复合索引时,需要根据实际的查询需求,将经常一起使用的列按照查询条件的顺序从左到右创建索引,以确保查询能够有效利用复合索引,提高查询性能。同时,在编写查询语句时,也需要注意遵循最左前缀法则,避免跳过最左列或在范围查询后使用后续索引列。

以下是最左前缀法则的案例说明。

环境准备

创建示例表:

CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY,last_name VARCHAR(50),first_name VARCHAR(50),age INT
);

创建复合索引:

CREATE INDEX idx_last_first_age ON users (last_name, first_name, age);

创建并执行存储过程:

-- 首先设置 delimiter 为 //,这样可以在存储过程中使用分号
DELIMITER //-- 创建存储过程 insert_users_data
CREATE PROCEDURE insert_users_data()
BEGIN-- 声明循环计数器变量 i,初始值为 1DECLARE i INT DEFAULT 1;-- 定义可能的姓氏数组DECLARE last_names TEXT DEFAULT 'Smith,Jones,Johnson,Brown,Wilson,Taylor,Davis,Miller,White,Clark';-- 定义可能的名字数组DECLARE first_names TEXT DEFAULT 'John,Michael,David,William,Richard,Joseph,Thomas,Charles,Christopher,Daniel';-- 开始循环,当 i 小于等于 100000 时执行循环体WHILE i <= 100000 DO-- 随机选择一个姓氏SET @last_name = SUBSTRING_INDEX(SUBSTRING_INDEX(last_names, ',', FLOOR(RAND() * 10) + 1), ',', -1);-- 随机选择一个名字SET @first_name = SUBSTRING_INDEX(SUBSTRING_INDEX(first_names, ',', FLOOR(RAND() * 10) + 1), ',', -1);-- 随机生成一个 18 到 60 岁之间的年龄SET @age = FLOOR(RAND() * 43) + 18;-- 向 users 表中插入一条记录INSERT INTO users (last_name, first_name, age) VALUES (@last_name, @first_name, @age);-- 计数器 i 加 1SET i = i + 1;END WHILE;
END //-- 将 delimiter 恢复为默认的分号
DELIMITER ;-- 调用存储过程
CALL insert_users_data();

符合最左前缀法则的查询

以下是符合最左前缀法则的查询示例。

示例 1:使用最左列查询

SELECT * FROM users WHERE last_name = 'Smith';

在这个查询中,只使用了复合索引的最左列 last_name。根据最左前缀法则,MySQL 可以直接使用 idx_last_first_age 索引来快速定位 last_name 为 ‘Smith’ 的记录,从而提高查询效率。

执行计划分析:

在这里插入图片描述

示例 2:使用最左两列查询

SELECT * FROM users WHERE last_name = 'Smith' AND first_name = 'John';

这里使用了复合索引的前两列 last_namefirst_name。MySQL 会先根据 last_name 进行筛选,然后在筛选结果中再根据 first_name 进行进一步筛选。由于符合最左前缀法则,这个查询也可以有效地利用复合索引。

执行计划分析:

在这里插入图片描述

不符合最左前缀法则的查询

以下是不符合最左前缀法则的查询示例。

示例 1:跳过最左列

SELECT * FROM users WHERE first_name = 'John';

在这个查询中,跳过了复合索引的最左列 last_name,直接使用了 first_name。根据最左前缀法则,MySQL 无法使用 idx_last_first_age 索引来优化这个查询,只能进行全表扫描,查询效率会比较低。

执行计划分析:

在这里插入图片描述

示例 2:范围查询后使用索引列

SELECT * FROM users WHERE last_name = 'Smith' AND first_name > 'Charles' AND age = 18;

在这个查询中,first_name > 'Charles' 是一个范围查询。根据最左前缀法则,MySQL 在遇到范围查询后,不会再使用后续的索引列(即 age)。因此,虽然查询中使用了 age 列,但它无法利用复合索引的这一部分,只能对 last_namefirst_name 进行索引查找,然后对剩余的记录进行全表扫描来筛选 age = 18 的记录。

执行计划分析:

在这里插入图片描述

实际上上述 SQL 的执行计划等同于:

SELECT * FROM users WHERE last_name = 'Smith' AND first_name > 'Charles'

这两个 SQL 的执行计划是完全相同的。即:

在这里插入图片描述

相关文章:

  • ISO和 IEC机构的区别
  • 信雅达 AI + 悦数 Graph RAG | 大模型知识管理平台在金融行业的实践
  • Microsoft .NET Framework 3.5 离线安装包 下载
  • 【动手学大模型开发】使用 LLM API:智谱 GLM
  • Python中的defaultdict方法
  • 信息过载(Information Overload):太多的信息导致了信息处理能力的饱和
  • JVM | CMS垃圾收集器详解
  • 基于tabula对pdf中的excel进行识别并转换成word(三)
  • FlexNoC-Latency
  • 进程自动守护,监控并自动重启
  • 完整的 SSL 证书生成与 Spring Boot 配置流程
  • MySQL下载与安装
  • 无人设备遥控器之移动手持定位系统篇
  • qtfaststart使用教程(moov置前)
  • MLOps全链路能力:模型监控、版本回滚与持续训练
  • 2025年- H13-Lc120-189.轮转数组(普通数组)---java版
  • MinIO中mc工具的安装、配置、简单使用
  • AI驱动软件工程:SoftEngine 方法论与 Lynx 平台实践分析
  • AI防摔倒检测系统
  • 华帝股份携手体验家,构建厨电终端服务体验管理闭环
  • 万科:一季度营收近380亿元,销售回款率超100%
  • 葡萄牙总理:未来几小时内将全面恢复供电
  • AI观察|算力饥渴与泡沫
  • 伊朗港口爆炸死亡人数升至70人
  • 亮剑浦江丨上海网信部门处罚一批医疗服务类互联网企业,三大类问题值得关注
  • 央视曝光假进口保健品:警惕!保税仓发货不等于真进口