在 MongoDB 中,索引是提高查询效率和性能的重要手段。然而,索引类型的选择和使用原则却是前端开发人员经常会遇到的问题。本文将介绍 MongoDB 中常见的索引类型以及它们的使用原则,帮助读者更好地选择和使用索引。
MongoDB 索引类型
单字段索引
单字段索引是最常见的索引类型,它只包含一个字段。例如,对于以下的用户数据集合:
{
"_id": ObjectId("5f2f6d4f4d3c3d2c1b7e6f91"),
"name": "Alice",
"age": 25,
"gender": "female",
"email": "alice@example.com",
"phone": "1234567890"
}可以为 name、age、gender、email、phone 等字段分别创建单字段索引:
db.users.createIndex({name: 1})
db.users.createIndex({age: 1})
db.users.createIndex({gender: 1})
db.users.createIndex({email: 1})
db.users.createIndex({phone: 1})其中,1 表示升序索引,-1 表示降序索引。
复合索引
复合索引是包含多个字段的索引类型,它可以提高多个字段的查询效率。例如,对于以下的订单数据集合:
{
"_id": ObjectId("5f2f6d4f4d3c3d2c1b7e6f92"),
"order_no": "202008080001",
"user_id": ObjectId("5f2f6d4f4d3c3d2c1b7e6f91"),
"status": "paid",
"created_at": ISODate("2020-08-08T00:00:01.000Z"),
"updated_at": ISODate("2020-08-08T00:00:02.000Z")
}可以为 user_id 和 created_at 字段创建复合索引:
db.orders.createIndex({user_id: 1, created_at: -1})其中,-1 表示降序索引,因为 created_at 字段的值通常是递增的,所以使用降序索引可以优化查询效率。
地理空间索引
地理空间索引是针对地理空间数据的索引类型,它可以用于查询地理位置相关的数据。例如,对于以下的商家数据集合:
{
"_id": ObjectId("5f2f6d4f4d3c3d2c1b7e6f93"),
"name": "Starbucks",
"location": {
"type": "Point",
"coordinates": [-73.9856644, 40.748817]
}
}可以为 location 字段创建地理空间索引:
db.stores.createIndex({location: "2dsphere"})其中,2dsphere 表示二维球面索引,适用于地球表面的地理空间数据。
索引使用原则
常用字段优先
对于经常用于查询和排序的字段,应该优先创建索引,以提高查询效率。例如,对于以下的文章数据集合:
// www.javascriptcn.com code example
{
"_id": ObjectId("5f2f6d4f4d3c3d2c1b7e6f94"),
"title": "JavaScript 优化技巧",
"content": "..."
"views": 100,
"likes": 50,
"created_at": ISODate("2020-08-08T00:00:01.000Z"),
"updated_at": ISODate("2020-08-08T00:00:02.000Z")
}可以为 views、likes 和 created_at 字段创建索引:
db.articles.createIndex({views: -1})
db.articles.createIndex({likes: -1})
db.articles.createIndex({created_at: -1})复合索引遵循最左前缀原则
对于复合索引,查询条件必须符合索引的最左前缀,否则索引无法起到优化查询的作用。例如,对于前面提到的订单数据集合,可以通过以下查询条件使用复合索引:
db.orders.find({user_id: ObjectId("5f2f6d4f4d3c3d2c1b7e6f91"), created_at: {$gte: ISODate("2020-08-08T00:00:00.000Z")}})这个查询条件符合复合索引的最左前缀 user_id,因此可以使用复合索引优化查询。
索引尽量覆盖查询条件
索引尽量覆盖查询条件可以减少查询的 IO 操作,提高查询效率。例如,对于以下的订单数据集合:
{
"_id": ObjectId("5f2f6d4f4d3c3d2c1b7e6f95"),
"order_no": "202008080002",
"user_id": ObjectId("5f2f6d4f4d3c3d2c1b7e6f91"),
"status": "paid",
"created_at": ISODate("2020-08-08T00:00:03.000Z"),
"updated_at": ISODate("2020-08-08T00:00:04.000Z")
}可以为 order_no 字段创建索引:
db.orders.createIndex({order_no: 1})然后,通过以下查询条件查询订单数据:
db.orders.find({order_no: "202008080002"}, {_id: 0, user_id: 1})这个查询条件只查询了 user_id 字段,而没有查询 status 和 created_at 字段。因为 user_id 字段已经在索引中,所以可以直接从索引中获取数据,而不需要再查询数据集合。
示例代码
下面是一个使用单字段索引的示例代码:
// 创建单字段索引
db.users.createIndex({name: 1})
// 查询用户数据
db.users.find({name: "Alice"}).explain("executionStats")输出结果:
// www.javascriptcn.com code example
{
"queryPlanner": {
"plannerVersion": 1,
"namespace": "test.users",
"indexFilterSet": false,
"parsedQuery": {
"name": {
"$eq": "Alice"
}
},
"winningPlan": {
"stage": "FETCH",
"inputStage": {
"stage": "IXSCAN",
"keyPattern": {
"name": 1
},
"indexName": "name_1",
"isMultiKey": false,
"multiKeyPaths": {
"name": []
},
"isUnique": false,
"isSparse": false,
"isPartial": false,
"indexVersion": 2,
"direction": "forward",
"indexBounds": {
"name": [
"[\"Alice\", \"Alice\"]"
]
}
}
},
"rejectedPlans": []
},
"executionStats": {
"executionSuccess": true,
"nReturned": 1,
"executionTimeMillis": 0,
"totalKeysExamined": 1,
"totalDocsExamined": 1,
"executionStages": {
"stage": "FETCH",
"nReturned": 1,
"executionTimeMillisEstimate": 0,
"works": 2,
"advanced": 1,
"needTime": 0,
"needYield": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"docsExamined": 1,
"alreadyHasObj": 0,
"inputStage": {
"stage": "IXSCAN",
"nReturned": 1,
"executionTimeMillisEstimate": 0,
"works": 2,
"advanced": 1,
"needTime": 0,
"needYield": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"keyPattern": {
"name": 1
},
"indexName": "name_1",
"isMultiKey": false,
"multiKeyPaths": {
"name": []
},
"isUnique": false,
"isSparse": false,
"isPartial": false,
"indexVersion": 2,
"direction": "forward",
"indexBounds": {
"name": [
"[\"Alice\", \"Alice\"]"
]
},
"keysExamined": 1,
"seeks": 1,
"dupsTested": 0,
"dupsDropped": 0,
"seenInvalidated": 0
}
},
"allPlansExecution": []
},
"serverInfo": {...},
"ok": 1
}以上就是 MongoDB 索引类型的选择与使用原则的详细介绍,希望对读者有所帮助。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d8ccdfa941bf7134f61e70