索引类型详解:从主键到全文,你该选哪个?

索引的类型,说白了就是给数据建目录的不同方式。每种类型都有它的脾气和适用场景。我这些年调过不少慢查询,有一半的问题出在索引选型上——不是没建,而是建错了类型。

咱们一个一个来看。

1. 主键索引(Primary Key)

这玩意儿是强制要求数据行唯一的。一张表最多只有一个主键索引。在 InnoDB 引擎里,它还是个聚簇索引。什么意思呢?就是数据本身跟索引长在一起。

特点:

  • 自动创建:建表时指定 PRIMARY KEY,MySQL 就会自动建成这个聚簇索引
  • 非空唯一:主键列不能为 NULL,值必须全局唯一
  • 物理排序:数据行按主键顺序物理存储

我遇到过的一个坑:

有次接手一个老系统,表里根本没有自增主键,用的是 UUID 做为主键。插入数据时页面卡死,查了一下,原因是 UUID 无序,每次插入都要大量页分裂。后来我改成自增 BIGINT,性能直接翻了三倍。

-- 创建表时指定主键
CREATE TABLE users (
    id BIGINT AUTO_INCREMENT,
    name VARCHAR(50),
    PRIMARY KEY (id)
);

2. 唯一索引(Unique Index)

唯一索引允许 NULL,但非空值必须唯一。你想想看,它跟主键索引的区别在哪?主键只能一个,唯一索引可以建多个。主键不能 NULL,唯一索引允许多个 NULL——嗯,这里要注意,MySQL 认为 NULL != NULL,所以多个 NULL 是允许的。

  • 约束数据:确保列值的唯一性(业务上常用,比如邮箱、身份证号)
  • 非聚簇:如果是二级唯一索引,不会改变数据物理存储
  • 可以联合:多列组合成唯一索引

我的习惯:

只要是业务上不能重复的字段,我都会建唯一索引。不只是为了查询,更多的是为了约束——让数据库替你把关,比业务层加锁靠谱得多。

-- 建唯一索引
CREATE UNIQUE INDEX idx_email ON users(email);

-- 或者建表时指定
CREATE TABLE users (
    id INT,
    email VARCHAR(100) UNIQUE
);

3. 普通索引(普通索引 / INDEX)

也叫非唯一索引,最常见,没有唯一性限制。说白了就是个单纯的加速器。允许重复值,允许 NULL。

我建议,凡是经常出现在 WHERE 条件里的列,都考虑建个普通索引。但别贪多——索引不是越多越好,写操作有代价。

适用场景:

  • 高频查询字段,如订单表的 user_id
  • 排序字段(ORDER BY)
  • 连接字段(JOIN)

曾经踩过的雷:

有一次我在一张 2000 万行的日志表上,对每个可能查询的列都建了普通索引,结果插入变慢,磁盘占用暴涨。后来我做了索引合并和冗余分析,删掉了一半的索引,性能才稳下来。

-- 创建普通索引
CREATE INDEX idx_order_time ON orders(created_at);

4. 全文索引(Fulltext Index)

全文索引是专为文本搜索设计的,你不用它去查数字或日期。它支持分词、停用词、相关度排序。MyISAM 和 InnoDB 都支持(MySQL 5.6 以后 InnoDB 才支持)。

我当时做一个新闻搜索模块,直接用 LIKE '%关键字%' 查,数据量一上来慢得要命。换成全文索引后,秒级出结果。

注意事项:

  • 只适用于 CHAR、VARCHAR、TEXT 类型
  • 默认最短分词长度:InnoDB 是 3 个字符
  • 需要使用 MATCH … AGAINST 语法,不是普通的 WHERE
-- 创建全文索引
CREATE FULLTEXT INDEX ft_content ON articles(content);

-- 查询用法
SELECT * FROM articles 
WHERE MATCH(content) AGAINST('数据库性能' IN NATURAL LANGUAGE MODE);

5. 其他索引补充

除了上面四种,实际工作中还有几个不得不提的:

  • 复合索引:多列组合成一个索引,最左前缀原则。我建议把选择性高的列放左边。
  • 空间索引(SPATIAL):用于地理数据类型(POINT、LINESTRING 等),MyISAM 支持,InnoDB 从 MySQL 5.7 开始支持。
  • 哈希索引(HASH):Memory 引擎默认,等值查询极快,但不支持范围查询和排序。

一句话总结:

主键索引管物理存储,唯一索引管业务约束,普通索引负责提速,全文索引管文本搜索。选型之前一定想清楚:你要的是什么能力?

各类型对比表

索引类型唯一性允许多个允许NULL聚簇典型引擎主要用途
主键索引是否(只能一个)否是(InnoDB)InnoDB数据物理组织 + 唯一标识
唯一索引是是多个NULL否InnoDB/MyISAM业务唯一约束 + 查询加速
普通索引否是是否InnoDB/MyISAM查询加速
全文索引否是是否InnoDB/MyISAM文本搜索(分词匹配)
MySQL 索引类型体系 索引类型 主键索引 (聚簇,唯一,非空) 唯一索引 (非聚簇,唯一) 普通索引 (非唯一,加速) 全文索引 (分词搜索) 数据物理排序 唯一标识行 自增ID最佳 业务唯一字段 允许NULL 可多列组合 高频查询列 排序/连接 注意覆盖索引 CHAR/VARCHAR/TEXT MATCH … AGAINST 分词长度3+ 复合索引 (多列组合) 遵循最左前缀原则,选择性高的列放前面

这张图把索引类型分成了四大类。每个大类下面,我又补充了实际使用时的核心要点。你可能会问:我实际建索引时该选哪个?我的建议是——先看业务需求。要唯一性约束吗?要文本搜索吗?要覆盖查询吗?想清楚这些,选型自然就有了。

最后分享一个小原则:能用普通索引解决的问题,就不要用唯一索引;只有确实需要约束唯一性时,才建唯一索引。因为唯一索引在插入时多了一次唯一性检查的代价。