一、索引是什么?
索引就是一种为了加速数据查询的、排好序的快速查找数据结构。
二、索引的核心:B+树
- 矮胖树,层级低:即使数据量有千万级,B+Tree 也只需要 3-4 层就能定位到数据。树的高度决定了磁盘 I/O 的次数,高度越低,查询越快。
- 数据全在叶子节点:所有实际的数据行地址都存储在最底层的叶子节点上。这使得上层的非叶子节点可以存放更多的索引键值,让树更“矮胖”。
- 叶子节点是双向链表:所有叶子节点之间用指针连成一个有序链表。这带来了一个巨大优势:非常适合范围查询
三、索引的优缺点
优点:大大加快数据查询速度:这是最核心的目的。
缺点:
- 占用磁盘空间:索引本身就是一张表,需要存储。
- 降低增、删、改的速度:因为数据变更时,不仅要改数据,还要更新索引树,维护排序。
重要结论:索引不是越多越好。应该只为那些常用于查询、排序、分组条件的列创建索引。
四、索引的类型
- 主键索引
- 一张表只能有一个。
- 要求唯一且非空。
- 叶子节点存储的是整行数据(聚簇索引)。
- 普通索引
- 最基本的索引,没有任何唯一性限制。
- 唯一索引
- 要求索引列的值必须唯一,但允许有空值。
- 联合索引
- 一个索引包含多个列。
- 核心原则:最左前缀匹配原则。
五、最左前缀原则(联合索引的灵魂)
如果你创建了一个 (name, age, position)
的联合索引,它相当于创建了以下三个索引:
(name)
(name, age)
(name, age, position)
你的查询条件必须从最左边的列 name
开始,否则索引就会失效
六、如何知道索引是否生效?(EXPLAIN 命令)
- type:查询类型。从好到坏:
system > const > eq_ref > ref > range > index > ALL
。至少要做到range
级别,如果看到ALL
就是全表扫描,需要优化。 - key:实际使用的索引名称。如果为
NULL
,说明没用到索引。 - rows:预估需要扫描的行数。越少越好。
- Extra:额外信息。
Using index
:恭喜,使用了覆盖索引,性能极佳。Using filesort
:需要额外的排序,通常需要优化。Using temporary
:需要创建临时表,性能差,必须优化。
七、索引失效的常见场景
- 查询条件包含
or
,可能导致索引失效 - 如果字段类型是字符串,
where
时一定用引号括起来,否则索引失效 like
通配符可能导致索引失效。- 联合索引,查询时的条件列不是联合索引中的第一个列,索引失效。
- 在索引列上使用 mysql 的内置函数,索引失效。
- 对索引列运算(如,
+、-、*、/
),索引失效。 - 索引字段上使用
(!= 或者 < >,not in)
时,可能会导致索引失效。 - 索引字段上使用
is null, is not null
,可能导致索引失效。 - 左连接查询或者右连接查询查询关联的字段编码格式不一样,可能导致索引失效。
- mysql 估计使用全表扫描要比使用索引快,则不使用索引。
八 hash索引和B+树索引的区别是什么?
- B+树可以进行范围查询,Hash 索引不能。
- B+树支持联合索引的最左侧原则,Hash 索引不支持。
- B+树支持 order by 排序,Hash 索引不支持。
- Hash 索引在等值查询上比 B+树效率更高。(但是索引列的重复值很多的话,Hash冲突,效率降低)。
- B+树使用 like 进行模糊查询的时候,like 后面(比如%开头)的话可以起到优化的作用,Hash 索引根本无法进行模糊查询
九 字符串加索引
方案 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
完整索引 | 最精准,支持所有查询 | 索引大,速度慢 | 字符串短,或查询模式复杂 |
前缀索引 | 索引小,速度快 | 不支持排序和覆盖扫描 | 最通用的优化方案,适用于大多数长字符串 |
倒序+前缀 | 解决前缀区分度低的问题 | 需要维护额外列,查询复杂 | 身份证号、手机号等尾部区分度高的字符串 |
哈希索引 | 索引极小,等值查询极快 | 仅支持等值查询,需处理冲突 | 只有等值查询需求的超长字符串(如URL) |
黄金法则:
- 字符串不长(几十个字符内) -> 直接全列索引。
- 字符串很长 -> 优先考虑前缀索引,并通过计算选择性找到最佳前缀长度。
- 字符串前缀区分度极低(如身份证) -> 考虑倒序存储 + 前缀索引。
- 只有等值查询需求 -> 可以考虑哈希索引。