阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 索引属性(唯一索引、稀疏索引、部分索引)

索引属性(唯一索引、稀疏索引、部分索引)

作者:陈川 阅读数:43838人阅读 分类: MongoDB

索引是MongoDB中优化查询性能的核心机制,通过不同类型的索引可以针对特定场景实现高效数据检索。索引属性包括唯一性、稀疏性和部分性,分别用于约束数据唯一、跳过空值字段和条件过滤。

唯一索引

唯一索引确保集合中每个文档的索引字段值不重复,类似关系型数据库中的UNIQUE约束。当插入或修改文档导致索引字段值重复时,MongoDB会抛出E11000 duplicate key error错误。

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

// 插入冲突数据会报错
db.users.insertMany([
  { email: "user1@example.com", name: "Alice" },
  { email: "user1@example.com", name: "Bob" }  // 抛出重复键错误
])

唯一索引的特殊情况包括:

  1. 允许存在多个null值,除非配合稀疏索引使用
  2. 复合唯一索引要求组合值唯一,单个字段可重复
  3. 分片集合中分片键默认具有唯一性
// 复合唯一索引示例
db.products.createIndex(
  { "category": 1, "sku": 1 }, 
  { unique: true }
)

// 以下插入操作是允许的
db.products.insertMany([
  { category: "electronics", sku: "A001" },
  { category: "furniture", sku: "A001" },  // 组合值不同
  { category: "electronics", sku: null }   // null值允许重复
])

稀疏索引

稀疏索引仅包含具有索引字段的文档条目,跳过字段不存在或值为null的文档。这种索引特别适合可选字段的场景,能显著减少索引存储空间。

// 创建稀疏索引
db.profiles.createIndex(
  { "social_media.twitter": 1 },
  { sparse: true }
)

// 以下文档中只有前两个会被索引
db.profiles.insertMany([
  { name: "A", "social_media": { twitter: "@a" } },
  { name: "B", "social_media": { twitter: "@b" } },
  { name: "C", "social_media": { facebook: "c" } },  // 无twitter字段
  { name: "D" }                                      // 无social_media字段
])

稀疏索引的典型应用场景:

  • 用户资料中的可选信息(如生日、地址)
  • 渐进式表单收集的非必填字段
  • 多态文档结构中的类型特定字段
// 稀疏复合索引示例
db.contacts.createIndex(
  { "phone": 1, "email": 1 },
  { sparse: true }
)

// 查询优化:使用稀疏索引加速存在性检查
db.contacts.find({
  phone: { $exists: true },
  email: { $exists: true }
}).explain("executionStats")

部分索引

部分索引仅索引满足指定过滤条件的文档,相比全集合索引能减少存储和维护成本。这种索引通过partialFilterExpression选项定义过滤逻辑。

// 创建部分索引:只索引status为"active"的文档
db.orders.createIndex(
  { "order_date": 1 },
  { 
    partialFilterExpression: { 
      status: "active",
      total: { $gt: 100 }
    }
  }
)

// 以下查询会使用该部分索引
db.orders.find({
  status: "active",
  total: { $gt: 150 },
  order_date: { $gt: ISODate("2023-01-01") }
})

部分索引设计要点:

  1. 过滤条件应使用高选择性的字段
  2. 可以组合稀疏索引特性使用
  3. 查询必须包含过滤条件或子集才能命中索引
// 复杂条件部分索引
db.logs.createIndex(
  { "timestamp": -1 },
  {
    partialFilterExpression: {
      $or: [
        { severity: "ERROR" },
        { response_time: { $gt: 1000 } }
      ]
    }
  }
)

// 等效查询示例
db.logs.find({
  timestamp: { $gt: ISODate("2023-06-01") },
  $or: [
    { severity: "ERROR" },
    { response_time: { $gt: 1200 } }
  ]
})

索引属性组合应用

实际场景中经常需要组合多种索引属性。例如创建同时具有唯一性和稀疏性的索引,可以解决null值重复问题。

// 唯一+稀疏索引组合
db.customers.createIndex(
  { "tax_id": 1 },
  { 
    unique: true,
    sparse: true 
  }
)

// 允许以下插入操作
db.customers.insertMany([
  { name: "A", tax_id: "123" },
  { name: "B" },                // 无tax_id字段
  { name: "C", tax_id: null },  // null值
  { name: "D" }                 // 无tax_id字段
])

// 但以下操作会因重复而失败
db.customers.insertOne({ name: "E", tax_id: "123" })

性能优化案例:电商平台商品集合

// 复合索引设计
db.products.createIndexes([
  // 唯一索引:商品编码
  {
    "product_code": 1,
    "vendor_id": 1
  },
  { unique: true },
  
  // 部分索引:热销商品
  {
    "category": 1,
    "sales_count": -1
  },
  {
    partialFilterExpression: {
      sales_count: { $gt: 1000 },
      stock: { $gt: 0 }
    }
  },
  
  // 稀疏索引:可选属性
  {
    "specifications.weight": 1
  },
  { sparse: true }
])

索引维护策略

创建索引后需要定期监控和维护:

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

// 索引重建示例
db.runCommand({
  compact: "collection",
  force: true,
  index: { name: "index_name" }
})

常见问题处理:

  1. 唯一索引冲突时可以使用writeConcern控制行为
  2. 部分索引需要确保查询计划器能正确选择
  3. 稀疏索引可能导致查询结果不一致

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌