索引属性(唯一索引、稀疏索引、部分索引)
索引是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" } // 抛出重复键错误
])
唯一索引的特殊情况包括:
- 允许存在多个
null
值,除非配合稀疏索引使用 - 复合唯一索引要求组合值唯一,单个字段可重复
- 分片集合中分片键默认具有唯一性
// 复合唯一索引示例
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") }
})
部分索引设计要点:
- 过滤条件应使用高选择性的字段
- 可以组合稀疏索引特性使用
- 查询必须包含过滤条件或子集才能命中索引
// 复杂条件部分索引
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" }
})
常见问题处理:
- 唯一索引冲突时可以使用
writeConcern
控制行为 - 部分索引需要确保查询计划器能正确选择
- 稀疏索引可能导致查询结果不一致
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:哈希索引与TTL索引
下一篇:索引的创建、查看与删除