索引设计需平衡查询效率与写入性能,优先为高频查询字段建索引,复合索引须按等值字段在前、范围字段在后的顺序设置,并定期清理冗余索引。

索引不是越多越好,也不是越少越省事。关键在于让查询快起来的同时,不拖慢写入和占用过多资源。移动端尤其明显——一次新增或更新操作可能触发多个索引重建,直接影响用户感知的响应速度。
按查询频率决定是否建索引
只给真正高频、有明确查询需求的字段建索引。比如用户列表页常按“status”筛选,消息列表常按“userId + timestamp”组合排序,这些就是优先级最高的索引目标。而像“createdAt”“updatedAt”这类仅用于日志或审计的字段,除非有明确范围查询场景,否则不必单独建索引。
- 统计页面埋点或 DevTools 的 Performance 面板,确认哪些查询实际耗时高、调用频次高
- 避免为“偶尔查一次”的字段建索引,尤其是低基数字段(如 status 只有 active/inactive 两种值)
- 在 Omi 或 Redux-Persist 等框架中,可通过自定义 persist adapter 控制哪些字段参与索引创建
复合索引字段顺序很重要
复合索引不是简单把几个字段堆在一起,顺序决定了它能覆盖哪些查询模式。IndexedDB 按照索引字段从左到右匹配,所以要把最常用于等值过滤的字段放前面,范围查询(如时间、价格)放后面。
- 例如:
createIndex('user_time', ['userId', 'timestamp'], { unique: false })能高效支持「某用户的所有消息」和「某用户最近10条消息(按 timestamp 倒序)」 - 但无法加速「所有用户在某时间段内的消息」——这时需要另一个以
timestamp开头的索引 - 如果查询中跳过了左侧字段(比如只查
timestamp),该复合索引基本失效
警惕“伪唯一”与低效键路径
用错键路径或误判唯一性,会让索引形同虚设。比如把 address.city 当作索引键路径,但数据里 address 有时是 null 或缺失,这条索引就对这部分记录完全不可用。
- 确保键路径在绝大多数数据中稳定存在;若字段可空,考虑预处理或使用默认值填充
-
unique: true仅适用于业务上绝对唯一的字段(如 user.id、order.sn),不要为了“看起来整洁”而滥用 - 避免嵌套过深的路径(如
a.b.c.d.e),解析开销会上升,且难以调试
定期评估与清理冗余索引
项目演进过程中,旧查询逻辑下线、字段语义变更、新功能引入,都可能导致某些索引长期闲置。它们仍在消耗写入性能,却不再带来收益。
- 升级 IndexedDB 版本时,可在
onupgradeneeded中检查并删除已废弃的索引 - 结合 Chrome DevTools 的 Memory 和 IndexedDB 面板,观察各索引的实际命中率(需配合自定义查询埋点)
- 参考 Mars 项目做法:每季度运行一次索引健康检查脚本,输出未被 used 超过 30 天的索引列表











