MySQL索引
索引为什么能提高 MySQL 查询效率?
索引就像一本书的目录,能让 MySQL 快速定位数据,避免全表扫描。
它一般是 B+ 树结构,查找效率是 O(log n),比从头到尾扫一遍数据要快得多
除了查得快,索引还能加速排序、分组、连接等操作。
项目中最常见的做法就是通过 create index 为经常用作查询条件的字段建索
能简单说一下索引的分类吗?
- 从功能上分类的话,有主键索引、唯一索引、全文索引;
- 从数据结构上分类的话,有 B+ 树索引、哈希索引;
- 从存储内容上分类的话,有聚簇索引、非聚簇索引。
主键索引和普通索引什么区别?
主键索引
在 InnoDB 中,主键索引就是 聚簇索引。
特点:
- 表数据本身按主键 B+ 树组织
- 叶子节点存的是整行数据
- 一张表只能有一个聚簇索引
- 主键不能为空,且唯一
普通索引
普通索引一般是 二级索引。
特点:
- 叶子节点存的是索引列值 + 主键值
- 查询如果不能直接从索引拿到全部字段,就需要根据主键再去聚簇索引中查一次,这个过程叫 回表
- 可以有多个普通索引
- 可以重复,也可以为 null(取决于具体约束)
核心区别
- 主键索引是聚簇索引,普通索引是二级索引
- 主键索引叶子节点存整行数据,普通索引叶子节点存主键值
- 主键索引天然唯一且不能为空,普通索引不一定
- 普通索引查询常常需要回表,主键索引直接定位整行
索引哪些情况下会失效呢?
比如索引列使用了函数、使用了通配符开头的模糊查询、联合索引不满足最左前缀原则,或者使用 or 的时候部分字段无索引等。
索引不适合哪些场景呢?
- 区分度低的列,可以和其他高区分度的列组成联合索引。
- 频繁更新的列,索引会增加更新的成本。
- TEXT、BLOB 等大对象类型的字段,可以使用前缀索引、全文索引替代。
- 当表的数据量很小的时候,不超过 1000 行,全表扫描可能比使用索引更快。
为什么 InnoDB 要使⽤ B+树作为索引?
因为 b+树是一种高度平衡的多路查找树,能够降低磁盘的读写次数,同时支持有序遍历和范围查找
哈希表不支持范围查找,二叉树层级太深,b 树不太方便范围扫描
B+树的叶⼦节点是单向链表还是双向链表?如果从⼤值向⼩值检索,如何操作?
B+树的叶⼦节点是通过双向链表连接的,这样可以⽅便范围查询和反向遍历。
当执⾏范围查询时,可以从范围的开始点或结束点开始,向前或向后遍历。
在需要对数据进⾏逆序处理时,双向链表⾮常有⽤。
如果需要在 B+树中从⼤值向⼩值进⾏检索,可以先定位到最右侧节点,找到包含最⼤值的叶⼦节点。从根节点开始向右遍历树的⽅式实现。
索引为什么⽤ B+树不⽤普通⼆叉树?
在极端情况下,普通二叉树会退化成为链表,这时候树的高度就等于数据量
此时查找 id=7 就需要 7 次 I/O 操作,相当于全表扫描。⽽ B+ 树作为多叉平衡树,能将数亿级的数据量控制在 3-4 层的树⾼,能极⼤减少磁盘的 I/O 次数
为什么不⽤平衡⼆叉树呢?
平衡⼆叉树虽然解决了普通⼆叉树的退化问题,但每个节点最多只有两个⼦节点的问题依然存在
聚族索引和⾮聚族索引有什么区别?
聚簇索引的叶⼦节点存储了完整的数据⾏,数据和索引是在⼀起的
聚簇索引的叶⼦节点只包含了主键值,需要通过回表按照主键去聚簇索引查找其他列的值,唯⼀索引、普通索引等⾮主键索引都是⾮聚簇索引
回表了解吗?
当使⽤⾮聚簇索引进⾏查询时, MySQL 需要先通过⾮聚簇索引找到主键值,然后再根据主键值回到聚簇索引中查找完整数据⾏,这个过程称为回表
覆盖索引了解吗?
覆盖索引指的是:查询所需的字段全部都在索引中,不需要回表,从索引⻚就能直接返回结果
可以将⾼频查询的字段(如 WHERE 条件和 SELECT 列)组合为联合索引,实现覆盖索引。
什么是最左前缀原则?
最左前缀原则指的是: MySQL 使⽤联合索引时,必须从最左边的字段开始匹配,才能命中索引。
一个性别字段,这个字段一定不能单独作一个索引吗
并不是说性别字段一定不能单独建索引,而是在绝大多数业务场景下,单独为性别字段建索引性价比极低、几乎没有实际价值,甚至可能带来性能损耗
数据库优化器在执行查询时,会判断是走索引还是全表扫描:
- 如果走性别索引:需要先查索引拿到符合条件的行 ID,再回表(访问主键索引)获取完整数据。但因为命中数据量太大(比如 50%),回表的 IO 开销远大于全表扫描
- 优化器最终会放弃使用这个索引,直接走全表扫描 —— 相当于建了索引但完全没用,还浪费了存储空间和写操作(插入 / 更新 / 删除时要维护索引)。