<返回目录     Powered by claud/xia兄

第8课: 索引管理

什么是索引?

索引是一种特殊的数据结构,用于快速查找数据。类似于书籍的目录,可以大幅提升查询性能。

查看索引

// 查看集合的所有索引
db.users.getIndexes()

// 默认返回_id索引
[
    {
        "v" : 2,
        "key" : { "_id" : 1 },
        "name" : "_id_"
    }
]

创建单字段索引

// 创建升序索引
db.users.createIndex({ age: 1 })

// 创建降序索引
db.users.createIndex({ age: -1 })

// 创建唯一索引
db.users.createIndex({ email: 1 }, { unique: true })

// 创建稀疏索引(只索引存在该字段的文档)
db.users.createIndex({ phone: 1 }, { sparse: true })

复合索引

// 创建复合索引(多个字段)
db.users.createIndex({ city: 1, age: -1 })

// 索引顺序很重要!
// 可以支持的查询:
// - { city: "北京" }
// - { city: "北京", age: 25 }
// 不能有效支持:
// - { age: 25 }  // 只查询第二个字段
复合索引规则:

查询条件必须包含索引的前缀字段才能使用索引。例如索引(a, b, c)可以支持查询(a)、(a,b)、(a,b,c),但不能支持(b)或(c)。

索引类型

类型 说明 示例
单字段索引 对单个字段建立索引 { age: 1 }
复合索引 对多个字段建立索引 { city: 1, age: -1 }
多键索引 对数组字段建立索引 { tags: 1 }
文本索引 全文搜索索引 { content: "text" }
地理空间索引 地理位置查询 { location: "2dsphere" }
哈希索引 用于分片键 { _id: "hashed" }

文本索引

// 创建文本索引
db.articles.createIndex({ title: "text", content: "text" })

// 文本搜索
db.articles.find({ $text: { $search: "MongoDB 教程" } })

// 每个集合只能有一个文本索引

地理空间索引

// 创建2dsphere索引(地球表面)
db.places.createIndex({ location: "2dsphere" })

// 插入地理数据
db.places.insertOne({
    name: "天安门",
    location: {
        type: "Point",
        coordinates: [116.397128, 39.916527]  // [经度, 纬度]
    }
})

// 查询附近的地点(5公里内)
db.places.find({
    location: {
        $near: {
            $geometry: {
                type: "Point",
                coordinates: [116.4, 39.9]
            },
            $maxDistance: 5000  // 米
        }
    }
})

索引选项

// unique - 唯一索引
db.users.createIndex({ email: 1 }, { unique: true })

// sparse - 稀疏索引
db.users.createIndex({ phone: 1 }, { sparse: true })

// expireAfterSeconds - TTL索引(自动删除过期文档)
db.sessions.createIndex(
    { createdAt: 1 },
    { expireAfterSeconds: 3600 }  // 1小时后自动删除
)

// partialFilterExpression - 部分索引
db.users.createIndex(
    { age: 1 },
    { partialFilterExpression: { age: { $gte: 18 } } }
)

// background - 后台创建(不阻塞数据库)
db.users.createIndex({ name: 1 }, { background: true })

删除索引

// 删除指定索引
db.users.dropIndex("age_1")

// 删除多个字段的索引
db.users.dropIndex({ city: 1, age: -1 })

// 删除所有索引(除了_id)
db.users.dropIndexes()

// 删除指定的多个索引
db.users.dropIndexes(["age_1", "email_1"])

查看索引使用情况

// 查看查询计划
db.users.find({ age: 25 }).explain("executionStats")

// 关键指标:
// - executionTimeMillis: 执行时间
// - totalDocsExamined: 扫描的文档数
// - totalKeysExamined: 扫描的索引键数
// - stage: "IXSCAN"表示使用了索引,"COLLSCAN"表示全表扫描

// 查看索引统计
db.users.aggregate([{ $indexStats: {} }])

索引设计原则

实战示例

// 电商系统索引设计
// 商品集合
db.products.createIndex({ category: 1, price: 1 })  // 分类浏览
db.products.createIndex({ name: "text" })  // 商品搜索
db.products.createIndex({ sales: -1 })  // 热销排行

// 订单集合
db.orders.createIndex({ userId: 1, createdAt: -1 })  // 用户订单
db.orders.createIndex({ status: 1 })  // 订单状态
db.orders.createIndex(
    { createdAt: 1 },
    { expireAfterSeconds: 7776000 }  // 90天后自动删除
)

// 用户集合
db.users.createIndex({ email: 1 }, { unique: true })
db.users.createIndex({ phone: 1 }, { unique: true, sparse: true })
练习题:
  1. 为users集合的email字段创建唯一索引
  2. 创建复合索引:city升序、age降序
  3. 为articles集合创建文本索引(title和content字段)
  4. 创建TTL索引,自动删除30天前的日志
  5. 使用explain()分析查询是否使用了索引
  6. 删除不再使用的索引