65.9K
CodeProject 正在变化。 阅读更多。
Home

继续学习 MongoDB 中的索引

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.80/5 (2投票s)

2018年3月6日

CPOL

3分钟阅读

viewsIcon

8871

继续学习 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文档,对吧,用户需要使用pricewarehouse位置来过滤相同的文档。 是的,我们需要构建一个查询。

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 或电子邮件中给我发送您的问题链接,如果可以的话,我一定会尽力帮助您。

© . All rights reserved.