MongoDB的复合索引

MongoDB 支持创建包含一个文档内的多个字段的复合索引。

例如某个主题活动的documents:

db.topic_photos

{
  "_id" : ObjectId("50b664372115fb21eca4b2b1"),
  "created_at" : ISODate("2012-11-28T19:21:27.528Z"),
  "featured" : true,
  "featured_at" : ISODate("2012-12-06T10:17:15.565Z"),
  "featured_by" : NumberLong(234234),
  "last_liked" : ISODate("2012-12-06T13:51:29.742Z"),
  "likes" : 386,
  "photo_id" : NumberLong("41136819156557824"),
  "topic_id" : NumberLong("38362556125028352"),
  "user_id" : NumberLong(3532432)
}

为了查询出该主题活动最受欢迎的图片,可以建立包含topic_id ,likes 和 created_at 字段的复合索引。

db.topic_photos.ensureIndex({"topic_id":1,"likes":-1,"created_at":-1})

任何使用索引中的前缀字段的查询都能命中复合索引。(Compound indexes support queries on any prefix of the fields in the index. )举个例子,使用topic_id 或者是 topic_id 和 likes 的查询都能命中索引。然而,以下查询的情况无法命中索引:

  • 只用 likes 查询
  • 只用 created_at 查询
  • 只用 likes 和 created_at 查询
  • 只用 topic_id 和 created_at 查询

当创建一个复合索引时,紧随索引字段的数字会指定索引的排序方式。1为升序,-1 为倒序。按何种方式排序并不影响随机访问,但却对利用复合索引进行带排序的查询很重要。

索引字段的顺序也非常关键。在上面的例子中,这个索引会包括首先按照第一个字段topic_id的值 排序,然后再按照likes 的值排序,最后才是按时间created_at 排序。

索引前缀(Index prefixes) 必须是索引字段的子集。例如,创建了索引{a:1, b:1, c:1},使用{a:1} 和 {a:1, b:1} 都是该索引的前缀。

提示:不用担心查询时字段的顺序。如果写查询语句 find({b:1,a:1}) 还是能够命中索引{a:1, b:1, c:1}。

总结

MongoDB的复合索引采用索引字段的前缀匹配,因此创建复合索引时,索引字段的顺序或 字段本身的排序非常重要。可以使用explain 查看 查询执行时是否命中索引。

对比
例如在MySQL 建立 topic_id,likes,created_at 三个字段的复合索引。
能够命中索引的查询:

  • 单独查询topic_id
  • 查询topic_id and likes
  • 查询topic_id and created_at
  • 查询所有列

不能命中索引的查询:

  • 单独查询likes
  • 单独查询 created_at
  • 查询 likes 和 created_at

参考资料