单字段与复合索引
本教程共 50 篇 · 第 41 篇 · 更新于 2026-07-30 · 约 4 分钟阅读
41. 单字段与复合索引
本节目标:会建单字段和复合索引,理解最左前缀匹配,并用 ESR 原则排好复合索引的字段顺序。
上一章说了索引为什么快。这一章讲具体怎么建,以及复合索引(Compound Index)的几个关键规则。
41.1 单字段索引
只对单个字段建索引,叫单字段索引(Single Field Index)。语法就是 createIndex({ 字段: 1 })。
// 给 products 的 category 建单字段索引
test> db.products.createIndex({ category: 1 })
之后按 category 过滤就能走索引。单字段索引简单,但遇到「又要等值、又要排序、又要范围」的复合查询就不够用了。
41.2 复合索引
复合索引是在多个字段上一起建的索引。字段按顺序组成键。
// 在 city、age 上建复合索引
test> db.users.createIndex({ city: 1, age: 1 })
这个索引先按 city 排序,同 city 内再按 age 排序。它能同时服务「按城市查」「按城市+年龄查」两类查询。
Tip一个复合索引可以顶多个单字段索引用,省下索引维护成本。别动不动就一个字段建一个索引。
41.3 最左前缀:顺序决定能用哪部分
复合索引遵循最左前缀(Leftmost Prefix)规则:查询必须用到索引的最左连续字段,索引才有效。
上面的 { city: 1, age: 1 } 索引,能支持:
{ city: "杭州" }✓ 用了最左字段{ city: "杭州", age: 28 }✓ 用了连续前缀{ age: 28 }✗ 跳过了最左的 city,用不上
// 这条能命中复合索引
test> db.users.find({ city: "杭州", age: { $gt: 25 } }).explain("queryPlanner")
Warning复合索引里字段顺序很重要。把「等值过滤」的字段放最左,范围或排序字段往后放,才能最大化利用前缀。
41.4 ESR 原则:怎么排字段顺序
面对一个典型查询,字段该怎么排?记住 ESR 三字诀:
- Equality(等值):先放做精确匹配的字段。
- Sort(排序):再放做排序的字段。
- Range(范围):最后放做范围匹配的字段。
例:经常按 city 等值查、按 age 排序、再按 created_at 做范围。索引应建为:
// ESR:city 等值 -> age 排序 -> created_at 范围
test> db.users.createIndex({ city: 1, age: 1, created_at: 1 })
// 完美契合 ESR 的查询
test> db.users.find({ city: "杭州" })
.sort({ age: 1 })
.filter({ created_at: { $gte: new Date("2025-01-01") } })
Note若把范围字段
created_at放在age前面,排序就吃不到索引了,会触发内存排序,性能掉下来。
41.5 索引命名
不指定时,索引名默认是字段和方向用下划线拼起来,比如 city_1_age_1。也可以自己起名:
test> db.users.createIndex(
{ city: 1, age: 1 },
{ name: "idx_city_age" }
)
建好后不能用重命名,只能删了重建。所以起个好懂的名字,后续运维会轻松些。
41.6 小结
单字段索引管一个字段,复合索引管多个。复合索引看最左前缀,字段顺序照 ESR(等值→排序→范围)排,查询才能既走索引又免排序。