10 分钟让你明白 MySQL 是如何利用索引的


一、前言

在MySQL中进行SQL优化的时候,经常会在一些情况下,对 MySQL 能否利用索引有一些迷惑。

譬如:

  1. MySQL 在遇到范围查询条件的时候就停止匹配了,那么到底是哪些范围条件?

  2. MySQL 在LIKE进行模糊匹配的时候又是如何利用索引的呢?

  3. MySQL 到底在怎么样的情况下能够利用索引进行排序?

今天,我将会用一个模型,把这些问题都一一解答,让你对MySQL索引的使用不再畏惧

二、知识补充

 key_len 

EXPLAIN执行计划中有一列 key_len 用于表示本次查询中,所选择的索引长度有多少字节,通常我们可借此判断联合索引有多少列被选择了。

在这里 key_len 大小的计算规则是:

  • 一般地,key_len 等于索引列类型字节长度,例如int类型为4 bytes,bigint为8 bytes;

  • 如果是字符串类型,还需要同时考虑字符集因素,例如:CHAR(30) UTF8则key_len至少是90 bytes;

  • 若该列类型定义时允许NULL,其key_len还需要再加 1 bytes;

  • 若该列类型为变长类型,例如 VARCHAR(TEXTBLOB不允许整列创建索引,如果创建部分索引也被视为动态列类型),其key_len还需要再加 2 bytes;

三、哪些条件能用到索引?

首先非常感谢登博,给了我一个很好的启发,我通过他的文章,然后结合自己的理解,制作出了这幅图

乍一看,是不是很晕,不急,我们慢慢来看

图中一共分了三个部分:

  1. Index Key :MySQL是用来确定扫描的数据范围,实际就是可以利用到的MySQL索引部分,体现在Key Length。

  2. Index Filter:MySQL用来确定哪些数据是可以用索引去过滤,在启用ICP后,可以用上索引的部分。

  3. Table Filter:MySQL无法用索引过滤,回表取回行数据后,到server层进行数据过滤。

我们细细展开。

Index Key 

Index Key是用来确定MySQL的一个扫描范围,分为上边界和下边界。

MySQL利用=、>=、> 来确定下边界(first key),利用最左原则,首先判断第一个索引键值在where条件中是否存在,如果存在,则判断比较符号,如果为(=,>=)中的一种,加入下边界的界定,然后继续判断下一个索引键,如果存在且是(>),则将该键值加入到下边界的界定,停止匹配下一个索引键;如果不存在,直接停止下边界匹配。

exp:idx_c1_c2_c3(c1,c2,c3)where c1>=1 and c2>2 and c3=1-->  first key (c1,c2)--> c1为 '>=' ,加入下边界界定,继续匹配下一个-->c2 为 '>',加入下边界界定,停止匹配

上边界(last key)和下边界(first key)类似,首先判断是否是否是(=,<=)中的一种,如果是,加入界定,继续下一个索引键值匹配,如果是(<),加入界定,停止匹配

exp:idx_c1_c2_c3(c1,c2,c3)where c1<=1 and c2=2 and c3<3--> first key (c1,c2,c3)--> c1为 '<=',加入上边界界定,继续匹配下一个--> c2为 '='加入上边界界定,继续匹配下一个--> c3 为 '<',加入上边界界定,停止匹配

注:这里简单的记忆是,如果比较符号中包含’=’号,’>=’也是包含’=’,那么该索引键是可以被利用的,可以继续匹配后面的索引键值;如果不存在’=’,也就是’>’,’<’,这两个,后面的索引键值就无法匹配了。同时,上下边界是不可以混用的,哪个边界能利用索引的的键值多,就是最终能够利用索引键值的个数。

 Index Filter 

字面理解就是可以用索引去过滤。也就是字段在索引键值中,但是无法用去确定Index Key的部分。

exp:idex_c1_c2_c3where c1>=1 and c2<=2 and c3 =1index key --> c1index filter--> c2 c3

注:这里简单的记忆是,如果比较符号中包含’=’号,’>=’也是包含’=’,那么该索引键是可以被利用的,可以继续匹配后面的索引键值;如果不存在’=’,也就是’>’,’<’,这两个,后面的索引键值就无法匹配了。同时,上下边界是不可以混用的,哪个边界能利用索引的的键值多,就是最终能够利用索引键值的个数。

 Index Filter 

字面理解就是可以用索引去过滤。也就是字段在索引键值中,但是无法用去确定Index Key的部分。

exp:idex_c1_c2_c3where c1>=1 and c2<=2 and c3 =1index key --> c1index filter--> c2 c3

这里为什么index key 只是c1呢?因为c2 是用来确定上边界的,但是上边界的c1没有出现(<=,=),而下边界中,c1是>=,c2没有出现,因此index key 只有c1字段。c2,c3 都出现在索引中,被当做index filter.

 Table Filter 

无法利用索引完成过滤,就只能用table filter。此时引擎层会将行数据返回到server层,然后server层进行table filter。

四、Between 和 Like 的处理

那么如果查询中存在between 和like,MySQL是如何进行处理的呢?

 Between 

where c1 between 'a' and 'b'等价于 where c1>='a' and c1 <='b',所以进行相应的替换,然后带入上层模型,确定上下边界即可。

 Like 

首先需要确认的是%不能是最在最左侧,where c1 like '%a' 这样的查询是无法利用索引的,因为索引的匹配需要符合最左前缀原则

where c1 like 'a%' 其实等价于 where c1>='a' and c1<'b' 大家可以仔细思考下。

五、索引的排序

在数据库中,如果无法利用索引完成排序,随着过滤数据的数据量的上升,排序的成本会越来越大,即使是采用了limit,但是数据库是会选择将结果集进行全部排序,再取排序后的limit 记录,而且 MySQL  针对可以用索引完成排序的limit 有优化,更能减少成本。

Make sure it uses index It is very important to have ORDER BY with LIMIT executed without scanning and sorting full result set, so it is important for it to use index – in this case index range scan will be started and query execution stopped as soon as soon as required amount of rows generated.

存在一张表,c1,c2,c3上面有索引,select c1,c2,c3 from t1; 查询走的是索引全扫描,因此呈现的数据相当于在没有索引的情况下select c1,c2,c3 from t1 order by c1,c2,c3; 的结果

因此,索引的有序性规则是怎么样的呢?

c1=3 —> c2 有序,c3 无序
c1=3,c2=2 — > c3 有序
c1 in(1,2) —> c2 无序 ,c3 无序

有个小规律,idx_c1_c2_c3,那么如何确定某个字段是有序的呢?c1 在索引的最前面,肯定是有序的,c2在第二个位置,只有在c1 唯一确定一个值的时候,c2才是有序的,如果c1有多个值,那么c2 将不一定有序,同理,c3也是类似

六、小结

针对MySQL索引,我这边只是提到了在单表查询情况下的模型,通过这篇文章,想必大家应该了解到MySQL大部分情况下是如何利用索引的,如果存在疑问,欢迎联系我。

「在看」吗?

<think>好的,我现在要帮用户解答如何学好SQL的问题。首先,我需要回忆自己学习SQL的经历,以及常见的教学方法和资源。用户可能是一个刚开始接触SQL的新手,或者有一定基础但想提高的人。他们可能希望得到系统性的学习步骤和实用的建议。 首先,我应该明确SQL的重要性,比如它在数据处理、数据分析、后端开发等领域的应用,这样用户能明白学习的价值。然后,考虑学习路径的结构。通常,学习SQL可以分为基础、进阶、实战和提升四个阶段,这样结构清晰,用户容易跟随。 基础部分需要涵盖基本概念,比如数据库、表、行、列,以及最基础的SELECT语句。这里要强调动手实践的重要性,安装MySQL或PostgreSQL这样的数据库软件,或者使用在线平台,比如SQL Fiddle。记得提醒用户不要只看教程,要多写代码。 接下来是进阶内容,包括复杂查询(如JOIN、子查询)、函数(聚合函数、字符串函数)、数据操作(INSERT、UPDATE、DELETE)和数据定义(CREATE TABLE、ALTER TABLE)。这里可能需要详细解释每个部分的重要性,比如JOIN在处理多表关联时的必要性,聚合函数在数据分析中的使用频率。 然后是实战练习,推荐一些练习平台,如LeetCode、HackerRank,这些地方有不同难度的题目。同时,建议用户参与实际项目,比如自己设计数据库,或者分析公开数据集。项目经验对巩固知识非常关键,用户可能在面试或工作中需要展示这些经验。 提升阶段,可以介绍优化技巧,比如索引的使用、EXPLAIN分析查询计划。这部分可能对中级用户更有帮助,但提前了解也有好处。另外,学习高级特性如窗口函数、存储过程,这些能提升用户的竞争力。推荐书籍和社区资源,比如《SQL必知必会》,Stack Overflow,帮助用户持续学习。 还要强调常见错误,比如忘记WHERE条件导致误删数据,SQL注入问题,提醒用户注意备份和使用参数化查询。这些是实际工作中容易遇到的问题,提前预警能减少用户的挫折感。 最后,保持学习的建议,比如参与开源项目、关注技术博客。定期复习和总结,帮助用户形成长期的学习习惯。 需要检查是否有遗漏的重要点,比如数据建模、范式理论,这些可能在进阶部分提到。另外,是否要推荐特定的工具或资源,比如推荐使用PostgreSQL还是MySQL?可能保持中立,让用户根据需求选择。还要确保语言口语化,避免过于技术化,让新手容易理解。 可能还需要加入一些激励的话,鼓励用户坚持练习,因为SQL入门容易精通难,持续实践是关键。检查步骤是否符合逻辑,是否覆盖了从基础到高级的所有必要内容,确保建议的实用性和可操作性。</think>学习SQL需要系统化的方法+持续实践,以下是分阶段学习路径和实用技巧: 一、基础搭建阶段(1-2周) 1. 理解核心概念 - 数据库=数据仓库,表=Excel工作表 - 行=记录,列=字段,主键=身份证号 - 重点掌握:SELECT, WHERE, ORDER BY 2. 安装实践环境(任选其一) ```sql -- 示例:创建表 CREATE TABLE students ( id INT PRIMARY KEY, name VARCHAR(50), score DECIMAL(5,2) ); -- 插入数据 INSERT INTO students VALUES (1, '张三', 85.5), (2, '李四', 92.0); ``` 二、进阶提升阶段(3-4周) 1. 掌握核心操作 - JOIN类型:INNER JOIN(交集)、LEFT JOIN(左表全保留) - 子查询:把查询结果当临时表 ```sql -- 多表关联示例 SELECT o.order_id, c.customer_name FROM orders o JOIN customers c ON o.customer_id = c.customer_id; ``` 2. 函数应用 - 聚合函数:COUNT/SUM/AVG 配合 GROUP BY - 时间函数:DATE_FORMAT/NOW()/DATEDIFF 三、实战训练阶段(持续进行) 1. 刷题平台推荐 - 新手:SQLZoo(免费交互式教程) - 中级:LeetCode数据库题库(企业真题) - 高级:HackerRank(复杂业务场景) 2. 真实项目实践 - 案例1:电商销售分析(计算复购率) - 案例2:图书馆管理系统(设计借阅关系表) ```sql -- 计算每月复购率 SELECT DATE_FORMAT(order_date, '%Y-%m') AS month, COUNT(DISTINCT user_id) AS total_users, SUM(repeat_purchase) / COUNT(*) AS repeat_rate FROM ( SELECT user_id, order_date, CASE WHEN COUNT(order_id) OVER(PARTITION BY user_id ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) >= 1 THEN 1 ELSE 0 END AS repeat_purchase FROM orders ) t GROUP BY 1; ``` 四、高手进阶路径 1. 性能优化 - 索引原理:B+树结构,适合范围查询 - 执行计划解读:EXPLAIN关键字分析 ```sql EXPLAIN SELECT * FROM products WHERE category = 'electronics' AND price > 1000; ``` 2. 学习延伸 - 事务处理:ACID原则 - 窗口函数:ROW_NUMBER()/RANK() - 存储过程开发 常见陷阱提醒: 1. 数据修改前必加WHERE条件 2. 字符串比较注意大小写敏感 3. 避免`SELECT *`消耗资源 学习资源推荐: - 书籍:《SQL进阶教程》MICK著 - 文档:MySQL 8.0官方手册 - 工具:DBeaver(多数据库客户端) 关键学习原则:每天保持30分钟实操,尝试用SQL解决实际问题(如分析个人消费记录)。遇到报错时仔细阅读错误信息,90%的问题都有明确提示。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值