【MongoDB系列 02】查询速度提升100倍!MongoDB索引设计全攻略
关键词: MongoDB索引、数据库索引优化、B-tree索引、复合索引、索引设计原则、查询性能优化、MongoDB性能调优、ESR规则、覆盖查询、索引监控
摘要: 索引是数据库性能优化的核心武器,也是MongoDB查询加速的秘密。本文从一个简单的性能问题出发,深入浅出地讲解MongoDB索引的工作原理、设计策略和优化技巧。我们将学习如何让查询速度提升100倍,掌握复合索引的ESR规则,理解覆盖查询的威力,以及构建完整的索引监控体系。无论你是MongoDB新手还是想要突破性能瓶颈的开发者,这篇文章都将为你打开高性能数据库应用的大门。
前言:一个让老板抓狂的性能问题
周一早上9点,你收到了来自老板的紧急消息:“用户反馈系统太慢了,查个用户信息要等10秒!这是什么情况?”
你赶紧打开监控面板,发现一个简单的用户查询竟然扫描了100万条记录!
// 这个看似简单的查询
db.users.find({
age: 25, status: "active"}).sort({
createdAt: -1}).limit(10)
// 竟然耗时 2.5 秒,扫描了 1,000,000 条文档!
这种情况你是否似曾相识?别担心,今天我们就来彻底解决这个问题。答案就在于索引设计。
什么是索引?用图书馆的故事来理解
图书馆的智慧
想象你在一个有百万册图书的图书馆里找一本关于"人工智能"的书。
没有索引的情况:
- 你只能从第一排书架开始,一本一本地翻找
- 可能需要几个小时才能找到目标书籍
- 这就像MongoDB的全表扫描
有索引的情况:
- 你直接查阅分类目录(索引)
- 目录告诉你"人工智能"类的书在第23排C区
- 3分钟内就能找到你想要的书
- 这就是索引查询的威力
MongoDB索引的本质
MongoDB的索引本质上就是一个排序的数据结构,它包含:
- 索引字段的值(如age: 25)
- 指向原始文档的指针
// 索引结构示意(简化版)
{
"age": 18 → 指向文档ID: ObjectId("...")
"age": 25 → 指向文档ID: ObjectId("...")
"age": 25 → 指向文档ID: ObjectId("...")
"age": 32 → 指向文档ID: ObjectId("...")
}
MongoDB索引类型全景图
1. 单字段索引:最基础也最重要
什么时候用:
- 经常基于某个字段查询
- 需要对某个字段排序
- 确保字段唯一性
// 创建升序索引
db.users.createIndex({
age: 1})
// 创建降序索引
db.users.createIndex({
createdAt: -1})
// 创建唯一索引
db.users.createIndex({
email: 1}, {
unique: true})
// 创建稀疏索引(跳过null值)
db.users.createIndex({
phone: 1}, {
sparse: true})
性能提升实例:
// 没有索引:扫描100万条记录
db.users.find({
age: 25}) // 2.5秒
// 有索引:直接定位
db.users.find({
age: 25}) // 0.003秒
// 性能提升833倍!
2. 复合索引:多条件查询的神器
复合索引是MongoDB性能优化的核心,它支持多个字段的组合查询。
// 创建复合索引
db.users.createIndex({
status: 1, // 第一个字段
age: 1, // 第二个字段
createdAt: -1 // 第三个字段
})
复合索引的强大之处:
// 以下查询都能使用上面的复合索引:
db.users.find({
status: "active"})
db.users.find({
status: "active", age: 25})
db.users.find({
status: "active", age: 25, createdAt: {
$gte: startDate}})
// 但这个查询无法使用索引(跳过了第一个字段):
db.users.find({
age: 25}) // ❌ 无法使用索引
3. 文本索引:全文搜索的利器
// 创建文本索引
db.articles.createIndex({
title: "text",
content: "text"
})
// 全文搜索
db.articles.find({
$text: {
$search: "MongoDB 索引优化"
}
})
// 支持中文分词搜索
db.articles.find({
$text: {
$search: "数据库 性能",
$language: "zh"
}
})
4. 地理空间索引:位置服务的基石
// 创建2dsphere索引(支持球面地理计算)
db.locations.createIndex({
position: "2dsphere"})
// 查找附近的餐厅(1公里内)
db.restaurants.find({
location: {
$near: {
$geometry: {
type: "Point",
coordinates: [116.404, 39.915