继续学习 MongoDB 中的索引






4.80/5 (2投票s)
继续学习 MongoDB 中的索引
引言
这是“和我一起学习 MongoDB”系列的第三篇文章。如果您还没有阅读我之前关于这个主题的文章,我强烈建议您在这里找到它。 这是对 MongoDB 索引的持续探索,我们将讨论可以在数据上执行的各种 MongoDB 索引。 我希望你会发现这篇文章有用。 感谢阅读。
和我一起学习 MongoDB
您可以在下面看到本系列的所有文章
背景
就像我说的,这将是该系列的第三部分。 我相信你现在对 Mongo DB 有足够的了解。 如果没有,请考虑再次阅读我之前的文章。
MongoDB 中的索引
让我们首先导入一个新的集合,products
。
[
{
"id":2,
"name":"An ice sculpture",
"price":12.50,
"tags":[
"cold",
"ice"
],
"dimensions":{
"length":7.0,
"width":12.0,
"height":9.5
},
"warehouseLocation":{
"latitude":-78.75,
"longitude":20.4
}
},
{
"id":3,
"name":"A blue mouse",
"price":25.50,
"dimensions":{
"length":3.1,
"width":1.0,
"height":1.0
},
"warehouseLocation":{
"latitude":54.4,
"longitude":-32.7
}
},
{
"id":4,
"name":"Keyboard",
"price":15.50,
"dimensions":{
"length":1.1,
"width":1.0,
"height":1.0
},
"warehouseLocation":{
"latitude":24.4,
"longitude":-42.7
}
},
{
"id":5,
"name":"Doll",
"price":10.50,
"dimensions":{
"length":5.1,
"width":1.0,
"height":7.0
},
"warehouseLocation":{
"latitude":64.4,
"longitude":-82.7
}
},
{
"id":6,
"name":"Wallet",
"price":5.50,
"dimensions":{
"length":1.1,
"width":1.0,
"height":1.0
},
"warehouseLocation":{
"latitude":24.4,
"longitude":-12.7
}
}
]
请注意,这些只是虚拟数据,可能对您来说听起来不合逻辑。
C:\Program Files\MongoDB\Server\3.4\bin>mongoimport --db mylearning
--collection products --jsonArray --file products.json
2018-03-06T16:48:34.440+0530 connected to: localhost
2018-03-06T16:48:34.607+0530 imported 5 documents
C:\Program Files\MongoDB\Server\3.4\bin>
如果您不知道导入命令的工作原理,请阅读我之前的文章,我们在其中看到了简单的索引。 现在我们有了数据,让我们执行索引。
单键索引
在本系列文章之前的文章中,我提到过简单的索引。 在本文中,我们不打算谈论它,而是探索 MongoDB 具有的另一种索引选项。 听起来不错? 如果是,让我们继续。 让我们去看看多键索引。
多键索引或复合索引
顾名思义,我们实际上要使用多个键元素设置索引。 在我们的products
集合中,我们有一些product
文档,对吧,用户需要使用price
和warehouse
位置来过滤相同的文档。 是的,我们需要构建一个查询。
MongoDB Enterprise > db.products.find({
... "price: {$lte: 16},
2018-03-06T17:10:15.005+0530 E QUERY
[thread1] SyntaxError: unterminated string literal @(shell):2:0
MongoDB Enterprise > db.products.find({
... "price": {$lte: 16},
... "warehouseLocation.latitude": {$gte: 60}
... })
{ "_id" : ObjectId("5a9e790a1ae1f955c1a70c4a"), "id" : 5, "name" : "Doll", "price" : 10.5,
"dimensions" : { "length" : 5.1, "width" : 1, "height" : 7 },
"warehouseLocation" : { "latitude" : 64.4, "longitude" : -82.7 } }
MongoDB Enterprise >
根据我们的搜索,我们得到一个条目,"price": {$lte: 16} and "warehouseLocation.latitude": {$gte: 60}
这太酷了。 现在让我们尝试找出相同的执行状态。
请注意,我们使用了$lte
和 $gte
,它们分别代表“小于或等于”和“大于或等于”,记住我之前告诉你的,“Mongo shell 很酷,我们可以用它做任何事情”。 现在让我们找出先前查找查询的已检查元素计数。
db.products.find({ "price": {$lte: 16}, "warehouseLocation.latitude":
{$gte: 60} }).explain("executionStats")
如果您的查询正确,您将得到如下结果
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "mylearning.products",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"price" : {
"$lte" : 16
}
},
{
"warehouseLocation.latitude" : {
"$gte" : 60
}
}
]
},
"winningPlan" : {
"stage" : "COLLSCAN",
"filter" : {
"$and" : [
{
"price" : {
"$lte" : 16
}
},
{
"warehouseLocation.latitude" : {
"$gte" : 60
}
}
]
},
"direction" : "forward"
},
"rejectedPlans" : [ ]
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 1,
"executionTimeMillis" : 107,
"totalKeysExamined" : 0,
"totalDocsExamined" : 5,
"executionStages" : {
"stage" : "COLLSCAN",
"filter" : {
"$and" : [
{
"price" : {
"$lte" : 16
}
},
{
"warehouseLocation.latitude" : {
"$gte" : 60
}
}
]
},
"nReturned" : 1,
"executionTimeMillisEstimate" : 0,
"works" : 7,
"advanced" : 1,
"needTime" : 5,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"direction" : "forward",
"docsExamined" : 5
}
},
"serverInfo" : {
"host" : "PC292716",
"port" : 27017,
"version" : "3.4.9",
"gitVersion" : "876ebee8c7dd0e2d992f36a848ff4dc50ee6603e"
},
"ok" : 1
}
您可能已经注意到我们为totalDocsExamined
设置的值,如果您还没有,请立即检查。 在我的例子中,它是5
,这意味着查询只检查了我们拥有的所有记录。 啊,听起来很糟糕,对吧? 如果我们的集合中有数百万条记录,那么获取结果需要多长时间?
MongoDB Enterprise > db.products.createIndex({price:1, "warehouseLocation.latitude":1})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
现在运行您之前的查询,并找出已检查的文档数的值。
MongoDB Enterprise > db.products.find({ "price": {$lte: 16},
"warehouseLocation.latitude": {$gte: 60} }).explain("executionStats")
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "mylearning.products",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"price" : {
"$lte" : 16
}
},
{
"warehouseLocation.latitude" : {
"$gte" : 60
}
}
]
},
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"price" : 1,
"warehouseLocation.latitude" : 1
},
"indexName" : "price_1_warehouseLocation.latitude_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"price" : [ ],
"warehouseLocation.latitude" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"price" : [
"[-inf.0, 16.0]"
],
"warehouseLocation.latitude" : [
"[60.0, inf.0]"
]
}
}
},
"rejectedPlans" : [ ]
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 1,
"executionTimeMillis" : 1089,
"totalKeysExamined" : 5,
"totalDocsExamined" : 1,
"executionStages" : {
"stage" : "FETCH",
"nReturned" : 1,
"executionTimeMillisEstimate" : 310,
"works" : 5,
"advanced" : 1,
"needTime" : 3,
"needYield" : 0,
"saveState" : 2,
"restoreState" : 2,
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 1,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 1,
"executionTimeMillisEstimate" : 270,
"works" : 5,
"advanced" : 1,
"needTime" : 3,
"needYield" : 0,
"saveState" : 2,
"restoreState" : 2,
"isEOF" : 1,
"invalidates" : 0,
"keyPattern" : {
"price" : 1,
"warehouseLocation.latitude" : 1
},
"indexName" : "price_1_warehouseLocation.latitude_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"price" : [ ],
"warehouseLocation.latitude" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"price" : [
"[-inf.0, 16.0]"
],
"warehouseLocation.latitude" : [
"[60.0, inf.0]"
]
},
"keysExamined" : 5,
"seeks" : 4,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
}
},
"serverInfo" : {
"host" : "PC292716",
"port" : 27017,
"version" : "3.4.9",
"gitVersion" : "876ebee8c7dd0e2d992f36a848ff4dc50ee6603e"
},
"ok" : 1
}
MongoDB Enterprise > db.products.find({ "price": {$lte: 16},
"warehouseLocation.latitude": {$gte: 60} })
{ "_id" : ObjectId("5a9e790a1ae1f955c1a70c4a"), "id" : 5, "name" : "Doll",
"price" : 10.5, "dimensions" : { "length" : 5.1, "width" : 1, "height" : 7 },
"warehouseLocation" : { "latitude" : 64.4, "longitude" : -82.7 } }
MongoDB Enterprise >
是的,我们得到了"docsExamined" : 1
,这就是我们想要的。 在您最常用的查询上创建一些索引,您肯定会看到一些神奇的效果。 您可以在 MongoDB 中的集合上创建多达 64 个索引,但您可能只需要创建几个,仅在您的顶级结果查询中。 你可以这样做,无论何时你在任何查询中遇到任何性能问题,都要考虑到它需要一些调整,并且肯定需要一个 Index
。 还有很多其他复杂的 Index
,但广泛使用的索引是单键索引和复合索引。
这样,我们就完成了这篇文章。 我将很快发布本系列的续篇。 到那时,再见。
结论
非常感谢您的阅读。 我是否遗漏了您认为需要的东西? 您觉得这篇文章有用吗? 我希望你喜欢这篇文章。 请分享您的宝贵建议和反馈。
现在轮到你了。你有什么想法?
没有评论的博客不是博客,但请尽量保持主题。 如果您有与此帖子无关的问题,最好将其发布在 C# Corner、Code Project、Stack Overflow、ASP.NET 论坛上,而不是在此处发表评论。 在 Twitter 或电子邮件中给我发送您的问题链接,如果可以的话,我一定会尽力帮助您。