程序员求职经验分享与学习资料整理平台

网站首页 > 文章精选 正文

(二十三) 程序员面试必备!MySQL索引底层逻辑+必坑指南

balukai 2025-05-09 17:03:39 文章精选 7 ℃

上一篇文章,笔者给大家讲了一下mysql 慢查询的定位方法和分析,那么这篇文章,将带大家学习一下,Mysql的解决慢查询的 一个重要方法之一就是使用索引

一.什么是索引(index)?

索引(Index)是存储引擎用于快速找到记录的数据结构,通过减少需要扫描的数据量来提高查询效率。是mysql 在数据之外,数据库系统保存着一套特定算法的数据结构(B+树),通过特定方式来指引数据.

索引是数据库的“智能目录”——就像图书馆的图书索引卡,通过预先建立特定字段的快速查找路径,让数据库不用翻遍所有数据就能秒级定位目标记录。

没有索引,我们就需要全盘扫描,一行一行的对比,查找出我们想要的数据,由来索引,就可以指向性的查找啦,就相当于有目录,直接找到了对应的额板块,大大降低的查找范围.

二. 索引的数据结构

mysql 底层主要是用的是B+ 树 来作为其数据存储和查询的结构 .

为什么不是使用二叉树?

  • 二叉树,数据结构不稳定,复杂度比较高
  • 二叉树,只有左右2个分叉,数据一旦多了,查询的层级会很多,效率不高,影响查询性能

存储100万数据时,树高20层 → 需20次磁盘IO, 实际场景中,树高每增加1层,查询性能下降30%

上面讲到,二叉树只有两个分叉,数据多了层级多,那么我们降低分层,让一层有多个分叉这样就有了B-tree树了

B-Tree 树是什么?

优点:

  • 减少磁盘IO次数:通过单个节点存储多个键值
  • 保持平衡:自动调整树结构,避免退化成链表

B树是一种自平衡的多路搜索树,每个节点最多包含m个子节点(m≥2),满足:

  • 根节点至少有两个子节点
  • 每个内部节点有m/2到m个子节点
  • 所有叶子节点位于同一层

当数据量大的时候,人们发现,查询会不断的返回父节点,确认数据范围,导致效率还是不够高,

那么还有没有更加优秀的数据结构了,当然是有了,这就是B树的升级版本B+树

什么是B+树?

传统B树在范围查询时需要频繁回溯父节点,导致磁盘IO暴增, 1972年Rudolf Bayer提出B+树,将数据全部下沉到叶子节点,非叶子节点仅作导航

数据验证:

(关键区别)非叶子节点和指针只做导航, 叶子节点才才存储数据

B+ 树对比B树的优点:

  • 磁盘读写效率更高
  • 查询效率B+树更加问题
  • B+树也更加适合扫库或者区间查询

Mysql 的InnoDB 搜索引擎 就是采用的 B+树的数据结构来存储索引哦

(什么InnoDB和什么又是MyISAM,持续关注,后面会给大家介绍,本章节主要是介绍索引为主 )

讲了索引的底层数据结构和其由来, 那么我们再看看索引有哪些区别吧.


三. 索引的分类

一.按照数据结构分类

1.B+ 树索引

适用场景:99%的MySQL索引类型,支持范围查询、排序、精确查找

实现引擎:InnoDB(聚簇/辅助索引)、MyISAM(非聚簇)

示例:

CREATE INDEX idx_age ON users(age); -- 普通B+树索引
  1. 哈希索引

特点:仅支持等值查询,O(1)时间复杂度

实现引擎:Memory引擎、InnoDB自适应哈希(AHI)

局限:不支持范围查询,易冲突

示例:

CREATE TABLE hash_table (  
    id INT,  
    INDEX USING HASH (id)  
) ENGINE=MEMORY;  
  1. 全文索引

分词算法:基于词干提取(英文)、ngram(中文)

支持类型:MyISAM(5.6前)、InnoDB(5.6+)

查询语法:

SELECT * FROM articles  
WHERE MATCH(content) AGAINST('数据库优化' IN NATURAL LANGUAGE MODE);  

二. 按照逻辑功能分类

三. 按照物理实现分类

聚簇索引(Clustered):数据行与索引绑定存储(InnoDB主键索引),减少回表,范围查询极速,插入可能引发页分裂问题.

[1,3,5,7] → 插入4 → 分裂为 [1,3] 和 [4,5,7]  

非聚簇索引(Secondary):也称二级索引 , 索引与数据分离(MyISAM索引、InnoDB辅助索引)

查询流程:查辅助索引 → 获取主键 → 回表查聚簇索引

通过二级索引只能找到部分数据,导致查询的数据不够,导致系统又返回聚簇索引索引中去查询整行数据.这个过程就称之为回表

(查询的时候* 就容易触发回表,所以要注意哦)

四.特殊索引

覆盖索引: 索引包含查询所需全部字段,避免回表,性能提升3-10倍

-- 创建覆盖索引  
CREATE INDEX idx_cover ON orders(user_id, status, amount);  
-- 触发覆盖  
SELECT user_id, status FROM orders WHERE user_id=100;  

覆盖索引也是解决超大分页的一个关键方法.

mysql 超大分页查询怎么提高查询速度?

直接使用limit查询速度慢, 覆盖索引+ 子查询即可

前缀索引: 长文本字段(如VARCHAR(255))

-- 计算最优前缀长度  
SELECT  
    COUNT(DISTINCT LEFT(content,10))/COUNT(*) AS len10,  
    COUNT(DISTINCT LEFT(content,15))/COUNT(*) AS len15  
FROM articles;  
-- 创建索引  
CREATE INDEX idx_content ON articles(content(15));  

降序索引: MySQL 8.0+:支持索引列降序排列,适用于ORDER BY id DESC LIMIT 高频查询

CREATE INDEX idx_time_desc ON logs(create_time DESC);  

四. 索引的创建原则?

  1. 针对数据量比较大的,且查询比较复杂的才建立索引
  2. 针对于where,order by, group by操作的字段
  3. 选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高
  4. 字符串类型的字段,字段的长度较长,可以针对于字段的特点,建立前缀索引
  5. 多使用联合索引,联合索引很多时候可以覆盖索引节省存储空间和避免回表提高查询效率。
  6. 控制索引的数量,不是越多越好,索引多了会影响增删的效率
  7. 如果索引列不能存储NULL值,请在创建表时使用NOT NULL约束它。当优化器知道每列是否包含NULL值时,它可以更好地确定哪个索引最有效地用于查询。

哪些场景会导致索引失效

就是索引没有触发,导致查询速度还是很慢的情况,就说明索引失效了,也可以使用explain 解析一下sql来判断是否索引失效

  • 1.违反最左侧法则:

多字段联合索引,索引会从最左边开始查询,且不通过索引列,匹配最左前缀

举例: 有一个联合索引 name+staus+ address,查询的时候直接跳过name 导致的失效

  • 2. 范围查询,右边的列不能使用索引

举例:status 使用了范围查询,右边的索引列adress就失效了

  • 3. 索引列上进行运算,导致索引失效

包括字段的截取,合并,已经数字字段的计算等

  • 4.字符串不加单引号,导致的索引失效

会导致数据类型发生转换,导致索引失效

  • 5. 模糊查询导致的索引失效

举例1: like查询为范围查询,%出现在左边,则索引失效。%出现在右边则索引未失效

like 失效的原因

  • %号在右: 由于B+树的索引顺序,是按照首字母的大小进行排序,%号在右的匹配又是匹配首字母。所以可以在B+树上进行有序的查找,查找首字母符合要求的数据。所以有些时候可以用到索引.
  • %号在左: 是匹配字符串尾部的数据,我们上面说了排序规则,尾部的字母是没有顺序的,所以不能按照索引顺序查询,就用不到索引.
  • 两个%%号: 这个是查询任意位置的字母满足条件即可,只有首字母是进行索引排序的,其他位置的字母都是相对无序的,所以查找任意位置的字母是用不上索引的.
最近发表
标签列表