图书馆的“索引目录”:MongoDB查询为什么这么快?

1. 什么是索引
假设图书馆里有 100万本书,现在让管理员帮你找一本《三体》。
如果图书馆没有任何分类和目录,管理员只能:
第1本、第2本、第3本……
一本一本找。
100万本书,要找到什么时候?
但现实中的图书馆不会这么干。通常会按照书名、作者、分类等建立目录。
管理员只需要:
《三体》 → 科幻类 → A区 → 12号书架
很快就能找到。
数据库中的索引,就是类似图书馆目录的东西。
索引可以帮助 MongoDB 更快地定位需要查询的数据,而不需要每次都把所有数据找一遍。
2. 为什么需要索引
假设有一个 books 集合:
{
name: "三体",
author: "刘慈欣",
category: "科幻"
}现在我们经常需要根据书名查询:
db.books.find({ name: "三体" })如果 name 没有建立索引,MongoDB 可能需要检查大量文档,判断它们的 name 是否是 "三体"。
这种方式就像:
管理员拿着书架上的书,一本一本检查。
数据量越大,需要检查的数据越多,查询可能就越慢。
如果我们给 name 建立索引:
db.books.createIndex({ name: 1 })就相当于:
给图书馆建立了一本“按照书名查找”的目录。
再次查询:
db.books.find({ name: "三体" })MongoDB 就可以利用这个索引快速定位相关数据。
3. MongoDB中如何创建索引
MongoDB创建索引非常简单:
db.books.createIndex({ name: 1 })这里的 1 表示升序索引。
也可以创建降序索引:
db.books.createIndex({ name: -1 })对于简单的等值查询来说,初学阶段可以先记住:
1表示升序,-1表示降序。
例如,我们经常根据作者查询:
db.books.find({ author: "刘慈欣" })那么可以建立:
db.books.createIndex({ author: 1 })这就相当于图书馆又增加了一本:
“按照作者查找”的目录。
4. 一个集合可以有多个索引吗?
当然可以。
例如:
db.books.createIndex({ name: 1 })
db.books.createIndex({ author: 1 })
db.books.createIndex({ category: 1 })现在图书馆就有了三本目录:
书名目录
作者目录
分类目录用户可以根据不同条件快速查找。
例如:
// 根据书名查
db.books.find({ name: "三体" })
// 根据作者查
db.books.find({ author: "刘慈欣" })
// 根据分类查
db.books.find({ category: "科幻" })不过,索引并不是越多越好。
5. 索引的代价
索引虽然可以提高查询速度,但并不是没有代价。
① 占用额外空间
回到图书馆的例子。
为了方便找书,我们建立了很多目录:
书名目录、作者目录、分类目录……
这些目录本身也需要占用空间。
MongoDB的索引同样需要占用额外的存储空间。
② 增加写操作的成本
假设图书馆新进了一本《三体》。
管理员不仅需要:
把书放到书架上
还需要:
更新书名目录、作者目录、分类目录……
MongoDB也是一样。
当我们新增、修改或者删除数据时,如果相关字段建立了索引,MongoDB还需要维护对应的索引。
因此:
索引可以提高查询性能,但也会增加写操作的维护成本。
③ 索引不是越多越好
如果图书馆为了方便查找,给每一个属性都建立目录:
书名目录
作者目录
出版社目录
价格目录
出版时间目录
页数目录
……目录越来越多,虽然查找方式越来越丰富,但管理员维护这些目录也会越来越麻烦。
MongoDB也是一样。
索引过多可能导致:
- 占用更多存储空间
- 增加数据写入成本
- 增加索引维护开销
- 一些索引可能长期都用不到
所以,建立索引应该根据实际的查询场景来决定。
6. 如何查看索引
我们可以使用:
db.books.getIndexes()查看当前集合的索引。
例如:
db.books.getIndexes()可能得到:
[
{
name: "_id_",
key: {
_id: 1
}
},
{
name: "name_1",
key: {
name: 1
}
}
]可以看到,MongoDB默认会为 _id 创建索引。
我们自己创建的 name 索引也出现在其中。
7. 怎么知道查询有没有使用索引?
MongoDB提供了一个非常有用的方法:
explain()例如:
db.books
.find({ name: "三体" })
.explain("executionStats")它可以帮助我们了解 MongoDB 是如何执行这次查询的。
初学阶段只需要先记住两个概念:
COLLSCAN表示扫描集合中的大量文档。
可以简单理解为:
管理员一本一本找书。
而:
IXSCAN表示使用了索引扫描。
可以理解为:
管理员先查目录,再根据目录找到书。
因此,当我们发现一个查询很慢时,可以使用 explain() 帮助分析:
MongoDB到底有没有使用我们创建的索引?
8. 总结
索引就像图书馆里的查询目录。
没有索引:
管理员只能一本一本找。
有了索引:
管理员可以先查目录,再快速定位目标。
MongoDB中的索引可以明显提高很多查询场景的效率,但索引也不是免费的:
它需要占用空间,也会增加数据写入时的维护成本。
所以,索引并不是越多越好,而应该根据实际业务中的查询条件和访问频率合理创建。
简单来说:
查询是“找书”,索引是“目录”,而
explain()就像是查看管理员到底有没有查目录。
这就是 MongoDB 索引最基本的概念。