第4章:索引设计原则——单列索引、复合索引、覆盖索引

索引这东西,在Room开发里就像一把双刃剑。用好了,查询快如闪电;用不好,写入慢得想哭。我记得刚入行那会儿,遇到一个列表加载特别慢的页面,我二话不说给每个字段都加了索引,结果写入操作直接崩了。后来才明白,索引不是越多越好,关键得知道怎么设计。

这一章我们就来聊聊三种最常用的索引类型:单列索引、复合索引、覆盖索引。我不会和你讲太多理论,而是结合我踩过的坑,说点能直接用上的东西。

单列索引:最基础的加速器

单列索引,说白了就是给一个字段建索引。比如你有一张用户表,经常根据 userId 来查,那就在这个字段上加索引。

CREATE INDEX idx_user_id ON User (userId);

在 Room 中,你需要在实体类上用 @Index 注解:

@Entity(indices = {@Index(value = "userId")})
public class User {
    @PrimaryKey
    public long id;
    public String userId;
    public String name;
}

这种索引适用于单一条件查询,比如:

SELECT * FROM User WHERE userId = ?;

速度提升很明显,但要注意——如果这个字段的区分度很低(比如性别字段只有男/女),索引的作用就很有限。我在一个项目中遇到过,给一个状态字段加了索引,结果扫描了几乎整张表,还不如全表扫描快。嗯,这里要绕开这个坑。

复合索引:多条件查询的利器

复合索引就是把多个字段绑在一起建索引。比如我们经常按 departmentId + createTime 来查记录:

CREATE INDEX idx_dep_time ON Employee (departmentId, createTime);

在 Room 中这样写:

@Entity(indices = {@Index(value = {"departmentId", "createTime"})})
public class Employee { ... }

使用复合索引有个核心原则叫“最左前缀”。什么意思?就是查询条件必须从索引的最左边开始匹配。比如 departmentId 是左边的字段,如果你只查 createTime 而忽略 departmentId,这个复合索引就派不上用场。

核心原则:复合索引的字段顺序决定查询效率。把区分度高的字段放左边,把等值查询字段放左边。

我之前优化过一个报表查询,原本有300万条数据,查询要5秒多。我把 region 和 date 建成复合索引,并且把 region 放左边(因为等值查询),查询时间直接降到80ms。你看,顺序不同,性能差距能差几十倍。

覆盖索引:让查询不走“回头路”

覆盖索引的概念稍微进阶一点。它是指:索引本身已经包含了查询所需的所有字段,数据库不需要再去表格里取数据(业务上叫“回表”)。

举个例子,假如我们经常做这个查询:

SELECT id, name, email FROM User WHERE email = ?;

如果只在 email 上建单列索引,查询时会先找到符合条件的行ID,然后再根据ID去主表中找 name 和 id。这就多了一次回表操作。

如果我们建一个复合索引 (email, id, name),那么索引本身就能满足查询,数据库直接返回结果,完全不用碰主表。这就是覆盖索引。

CREATE INDEX idx_cover ON User (email, id, name);
小技巧:在复合索引中把要查询的字段都包含进去,但不要过多,否则索引本身会变得很大,影响写入性能。

三种索引的对比

索引类型适用场景优点缺点
单列索引单一字段频繁等值或范围查询简单、开销小多条件组合查询时效率低
复合索引多字段组合查询(等值+排序/范围)按最左前缀兼容多种查询字段顺序要求严格,写放大
覆盖索引查询字段全部在索引内避免回表,IO极低索引体积大,更新开销高

避坑指南

我曾经接手过一个已上线的项目,业务方反馈某列表页滑动卡顿。我一看,表里有7个单列索引,但查询却用了三个条件的组合查询。7个索引没有一个能直接命中。我重建了一个复合索引,字段顺序按 status、type、createTime 排列(因为status和type都是等值查询,createTime用于排序),修改后效果立竿见影。

所以我的建议是:

  • 先分析常用查询条件,再决定用单列还是复合。
  • 复合索引的字段顺序:等值查询放最左,然后范围查询或排序字段。
  • 能用覆盖索引时尽量用,但要控制字段数量,别超过5个。
千万别做:为了一张表建超过5个索引!SQLite的写入性能会急剧下降。我见过有人建了12个索引,写入一条数据要等好几秒。

好了,三种索引设计原则讲完了。你可以在自己的项目里试试,做一个查询分析,看看哪些查询需要改进。

索引设计决策关系图 查询条件分析 单字段等值/范围查询 多字段组合查询 查询字段都在索引中 建立单列索引 建立复合索引 建立覆盖索引 注意事项:字段区分度、最左前缀、索引数量控制 根据查询模式选择最优索引组合 避免冗余索引,平衡读写性能