InnoDB 中索引类型有哪些?

#中间件#面试八股

InnoDB 中索引类型有哪些?

结论:按数据结构分有四类——B+Tree、全文(倒排)、空间(R-Tree)、自适应哈希;按业务用途分有主键、唯一、普通、联合、前缀、函数、降序索引。面试里说清「结构维度」与「用途维度」两条线,再补 8.0 的不可见索引与索引跳跃扫描,就比较完整。

一、两条分类线

按数据结构                        按用途
├── B+Tree(默认,绝大多数)      ├── 主键索引(聚簇)
├── 全文索引 FULLTEXT(倒排)      ├── 唯一索引
├── 空间索引 SPATIAL(R-Tree)     ├── 普通索引(二级)
└── 自适应哈希 AHI(自动,非显式)  ├── 联合索引
                                  ├── 前缀索引
                                  ├── 函数索引(8.0.13+)
                                  └── 降序索引(8.0+)

二、按数据结构

类型实现适用限制
B+Tree多路平衡树,叶子有序链表等值、范围、排序、前缀匹配前导模糊 %x 不可用
全文 FULLTEXT倒排索引 + 分词大段文本关键词检索需配置分词器,中文效果有限
空间 SPATIALR-Tree经纬度、几何包含判断列必须 NOT NULL,仅 MyISAM/InnoDB 支持
自适应哈希 AHI缓冲池页的哈希表热点等值查询由 innodb_adaptive_hash_index 自动管理,不可手动建

三、按用途:建法与要点

主键索引:一张表一个,叶子存整行。

CREATE TABLE t_order (
  id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (id)
) ENGINE=InnoDB;

唯一索引、普通索引、联合索引:

ALTER TABLE t_order
  ADD UNIQUE KEY uk_order_no (order_no),        -- 唯一
  ADD KEY idx_user_status (user_id, status),    -- 联合,注意列顺序
  ADD KEY idx_ctime (ctime);                    -- 普通

前缀索引:长字符串只索引前 N 个字符,省空间。

ALTER TABLE t_article ADD KEY idx_title (title(20));

-- 选 N:比较前缀区分度与整列区分度
SELECT
  COUNT(DISTINCT LEFT(title, 10)) / COUNT(*) AS sel_10,
  COUNT(DISTINCT LEFT(title, 20)) / COUNT(*) AS sel_20,
  COUNT(DISTINCT title) / COUNT(*)            AS sel_full
FROM t_article;

前缀索引无法用于覆盖索引,也无法支持 ORDER BY title,这是它的硬伤。

函数索引(8.0.13+,本质是隐藏的生成列 + 索引):

ALTER TABLE t_user
  ADD KEY idx_phone_tail ((RIGHT(phone, 4)));

-- 查询必须写成与索引表达式一致的形式才能命中
SELECT id FROM t_user WHERE RIGHT(phone, 4) = '8888';

降序索引(8.0+,真正按 DESC 存储,而不是反向扫描):

ALTER TABLE t_order ADD KEY idx_user_ctime (user_id, ctime DESC);

SELECT * FROM t_order
WHERE user_id = 42
ORDER BY ctime DESC
LIMIT 20;

不可见索引(8.0+,用于安全下线索引):

ALTER TABLE t_order ALTER INDEX idx_ctime INVISIBLE;
-- 观察业务无异常后再真正删除
ALTER TABLE t_order DROP INDEX idx_ctime;

四、索引跳跃扫描(Skip Scan)

8.0.13 引入:联合索引 (a, b) 在查询只带 b 时,若 a 的取值很少,优化器可以逐个枚举 a 的值做多次等值探测,等价于「跳过最左列」。

ALTER TABLE t_order ADD KEY idx_status_user (status, user_id);

-- status 只有 5 种取值时可能触发 skip scan
EXPLAIN SELECT * FROM t_order WHERE user_id = 42;
-- Extra: Using index for skip scan

它是优化器的补救手段,不是设计依据:能按最左前缀建索引就不要指望它。

常见追问

  • 自适应哈希索引需要手动建吗? 不需要,InnoDB 自动为热点页建哈希,SHOW ENGINE INNODB STATUS 的 INSERT BUFFER AND ADAPTIVE HASH INDEX 段能看到命中率。
  • 全文索引能替代 Elasticsearch 吗? 小数据量可以,中文分词、相关性排序、聚合分析都不如 ES,且全文索引与事务、复制的配合较弱。
  • 一张表能建多少个索引? 上限 64 个,但实际超过 5 个就要审视写入放大了。
  • 函数索引和「在列上用函数」有什么区别? 后者让普通索引失效;函数索引把表达式物化成生成列再建索引,两者正好相反。
  • 降序索引解决了什么问题? 联合索引中「一部分升序、一部分降序」的排序,8.0 之前只能 filesort。
  • 前缀索引的长度怎么定? 让前缀区分度接近整列区分度即可,通常 10~20 个字符,配合上面的区分度 SQL 实测。

小结

结构维度回答「用什么算法组织键」,用途维度回答「这条索引服务哪个查询」。生产建索引先问三件事:查询的最左前缀是什么、能不能覆盖、写放大是否可接受;剩下的全文、空间、函数、降序索引都是特定场景的专用工具。

笔记加载中…