MongoDB 索引限制
                           
天天向上
发布: 2025-03-09 09:34:15

原创
596 人浏览过

MongoDB 索引提高了查询性能,但也有一些限制和注意事项,在设计数据库时需要了解这些限制,以避免潜在的性能问题和错误。


1. 每个集合的最大索引数量

  • MongoDB 限制:每个集合最多可以创建 64 个索引(包括 _id 索引)。
  • 影响
  • 索引过多会增加存储开销,影响写入性能(因为每次插入、更新都需要更新索引)。
  • 应该合理规划索引,避免创建不必要的索引。

2. 索引字段大小限制

  • MongoDB 限制
  • 单个索引项的大小(索引键+索引元数据)不能超过 1024 字节
  • 适用于 BSON 字段值、字符串、数组等
  • 影响
  • 超长字符串索引可能会失败
    js db.articles.createIndex({ title: 1 })
    如果 title 太长,索引可能无法创建。
  • 解决方案:
    • 使用哈希索引
      js db.articles.createIndex({ title: "hashed" })
    • 截取字段值存储短哈希

3. 复合索引字段顺序

  • MongoDB 限制
  • 复合索引字段顺序很重要,查询时必须匹配索引的前缀字段才能利用索引。
  • 影响
  • 索引 { A: 1, B: 1 }
    • db.collection.find({ A: 10 }) 能使用索引
    • db.collection.find({ A: 10, B: 20 }) 能使用索引
    • db.collection.find({ B: 20 }) 不能使用索引
  • 解决方案:
    • 根据查询习惯优化索引顺序最常用的字段放前面

4. 多键索引(Multikey Index)限制

多键索引用于数组字段索引,但有一些限制:

  • 不能用于
  • 复合索引的多个字段都包含数组(MongoDB 无法索引多个数组组合)。
  • 覆盖查询(因为索引存储方式不同)。
  • 示例(错误案例)
  db.products.createIndex({ tags: 1, categories: 1 }) // ❌ tags 和 categories 都是数组
  • 正确方式
  • 仅索引一个数组字段
    js db.products.createIndex({ tags: 1 }) // ✅
  • 分开查询,不要依赖复合索引。

5. 唯一索引与 null

  • MongoDB 限制
  • 唯一索引(unique: true)不会阻止多个文档的 null,MongoDB 认为 null 值不算重复。
  • 示例
  db.users.createIndex({ email: 1 }, { unique: true })
  • 允许多个 email: null 进入集合,因为 null 在唯一索引中不算冲突。
  • 解决方案
  • 使用 部分索引 限制 null 值:
    js db.users.createIndex( { email: 1 }, { unique: true, partialFilterExpression: { email: { $exists: true } } } )
  • 这样,只有 email 存在时才会被索引,避免多个 null 存在。

6. TTL 索引的限制

TTL(Time-To-Live)索引用于自动删除过期文档,但有以下限制:

  • 只能用于 Date 类型字段,不能用于 NumberString 类型。
  • TTL 索引的时间间隔不是精确的,MongoDB 约60 秒扫描一次并删除过期文档。
  • 无法手动删除 TTL 索引管理的文档,只能等 MongoDB 处理。
  • 示例
  db.sessions.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 })
  • createdAt 必须是 Date 类型,否则 MongoDB 不会自动删除。

7. 哈希索引限制

哈希索引用于等值查询,但不能用于范围查询$gt$lt)。

  • 示例(错误案例)
  db.users.createIndex({ userId: "hashed" })
  db.users.find({ userId: { $gt: "abc" } }) // ❌ 不能使用索引
  • 正确方式
  • 如果需要范围查询,应该使用普通索引:
    js db.users.createIndex({ userId: 1 }) // ✅ 可用于范围查询

8. 覆盖索引(Covered Query)限制

MongoDB 只有在查询的字段都在索引内,且不查询 _id 时,才能进行覆盖索引查询

  • 示例(正确方式)
  db.users.createIndex({ name: 1, age: 1 })
  db.users.find({ name: "Alice" }, { name: 1, age: 1, _id: 0 }) // ✅ 覆盖索引
  • 示例(错误方式)
  db.users.find({ name: "Alice" }, { name: 1, age: 1 }) // ❌ 由于 _id 默认返回,无法覆盖索引
  • 解决方案
  • 显式排除 _id,确保查询的字段都在索引内。

9. 大量写入时索引影响性能

索引会影响写入(插入、更新、删除)性能,因为每次写入时,MongoDB 都需要同步更新索引。

  • 建议
  • 批量插入前,可以先删除索引,然后再重新创建:
    js db.collection.dropIndexes() // 删除所有索引 // 进行批量插入 db.collection.createIndex({ field: 1 }) // 重新创建索引
  • 避免在高写入负载下创建多个索引,尽量优化索引结构。

10. Oplog(复制集)和索引限制

MongoDB 复制集(Replica Set) 依赖 oplog,但如果索引过大,会影响同步性能:

  • 问题
  • 索引过大会占用 oplog 空间,导致主从复制性能下降。
  • 优化
  • 减少不必要的索引
  • 优化查询模式,减少索引负担。

总结

限制类型影响解决方案
索引数量限制每个集合最多 64 个索引只创建必要索引
索引大小限制单个索引项 ≤1024 字节使用哈希索引或短字段
复合索引顺序必须匹配前缀顺序选择合理索引顺序
多键索引限制不能索引多个数组字段仅索引单个数组
唯一索引 nullnull 不受唯一约束影响使用部分索引
TTL 索引限制仅支持 Date 类型确保字段类型正确
哈希索引限制不能做范围查询用普通索引
覆盖索引限制必须查询所有索引字段显式排除 _id
高写入影响索引写入性能下降先删除索引再批量插入

更多详细内容请关注其他相关文章!

发表回复 0

Your email address will not be published. Required fields are marked *