猿教程 Logo

.Net连接MongoDb:复合索引

阿里云服务器,每月低至7.8元,项目演示即建站必备,比腾讯云更便宜,并且不需学生认证,从此链接购买有效:去购买

介绍

在上一篇文章中,我们使用Mongo shell创建了我们的邮政编码集合的第一个索引。 我们在国家财产上插入了一个文本。 我们还引入了explain函数,该函数根据函数的布尔参数提供查询计划,还可以执行或不执行查询。 在创建索引之前和之后运行explain函数是一个很好的策略。 您的目标应该是尽可能减少扫描文件的数量。

在这篇文章中,我们将看一下复合索引。

复合索引

复合索引是由集合的两个或多个属性组成的索引。 如果频繁查询涉及多个过滤器,则它们非常有用。 我们可以从餐厅收集一个例子。 这是一个示例文档:

db.restaurants.findOne()
{
        "_id" : ObjectId("56edc2ff03a1cd840734dba8"),
        "address" : {
                "building" : "2780",
                "coord" : [
                        -73.98241999999999,
                        40.579505
                ],
                "street" : "Stillwell Avenue",
                "zipcode" : "11224"
        },
        "borough" : "Brooklyn",
        "cuisine" : "American ",
        "grades" : [
                {
                        "date" : ISODate("2014-06-10T00:00:00Z"),
                        "grade" : "A",
                        "score" : 5
                },
                {
                        "date" : ISODate("2013-06-05T00:00:00Z"),
                        "grade" : "A",
                        "score" : 7
                },
                {
                        "date" : ISODate("2012-04-13T00:00:00Z"),
                        "grade" : "A",
                        "score" : 12
                },
                {
                        "date" : ISODate("2011-10-12T00:00:00Z"),
                        "grade" : "A",
                        "score" : 12
                }
        ],
        "name" : "Riviera Caterer",
        "restaurant_id" : "40356018"
}

我们可以想象,一个频繁的查询将过滤自治市镇和美食属性。 例如。 给我所有在曼哈顿的泰国餐馆:

db.restaurants.find({"borough" : "Manhattan", "cuisine" : "Thai"})

解释命令...

db.restaurants.explain(true).find({"borough" : "Manhattan", "cuisine" : "Thai"})

...会告诉我们以下内容:

  • 在自治市镇或美食领域没有任何索引的情况下,MongoDb执行完整的查询扫描 - 在获奖计划子文档中回忆COLLSCAN阶段

  • 系统返回154个文件,扫描所有25362个文件

我们试着改进这个。 我们将首先看看自治市镇领域的单一索引是否有帮助。 插入以下索引:

db.restaurants.createIndex({"borough" : 1})

我们没有为索引提供任何名称。 MongoDb将给它一个默认名称(property_name)_(1或-1,无论是升序还是降序),例如:

borough_1
state_-1

运行相同的说明命令给我们以下内容:

  • 用行政指数进行索引扫描

  • 索引扫描返回了10259个文档,这是集合中曼哈顿的餐馆数量

  • 因此,扫描文件总数为10259个,与以前相比至少有一些改善

以下是查询计划的相关位,以支持以上内容 - 我已经删除了“噪音”:

"winningPlan" : {
                        "stage" : "FETCH",
                        "filter" : {
                                "cuisine" : {
                                        "$eq" : "Thai"
                                }
                        },
                        "inputStage" : {
                                "stage" : "IXSCAN",
                                "keyPattern" : {
                                        "borough" : 1
                                },
                                "indexName" : "borough_1",

...

 "executionStats" : {                
                "nReturned" : 154,
                
                "totalDocsExamined" : 10259,
                "executionStages" : {
                        "stage" : "FETCH",
                        "filter" : {
                                "cuisine" : {
                                        "$eq" : "Thai"
                                }
                        },
                        "nReturned" : 154,                        
                        "docsExamined" : 10259                        
                        "inputStage" : {
                                "stage" : "IXSCAN",
                                "nReturned" : 10259,
                                
                                "indexName" : "borough_1",
                                
        },

因此,我们共有2个阶段。 首先是索引扫描阶段,返回10259个文档,即曼哈顿的餐馆。 然后我们有一个FETCH舞台,其中所有10259个文档在烹饪领域进行扫描和过滤。

看看复合指数是否可以进一步改善结果。 首先我们用dropIndex函数去除索引。 dropIndex函数接受与我们创建的索引相同的JSON参数:

db.restaurants.dropIndex({"borough" : 1})

以下命令将在自治区和美食领域创建一个复合索引:

db.restaurants.createIndex({"borough" : 1, "cuisine" : 1})

现在运行explain函数会告诉我们:

  • 复合索引确实用于执行查询

  • 索引扫描阶段返回154个文档

  • 检查的文档总数为154,也等于查询返回的文档数

  • 总执行时间为1毫秒

以下是查询计划的一些相关详细信息:

"winningPlan" : {
                        "stage" : "FETCH",
                        "inputStage" : {
                                "stage" : "IXSCAN",
                                "keyPattern" : {
                                        "borough" : 1,
                                        "cuisine" : 1
                                },
                                "indexName" : "borough_1_cuisine_1",

...

 "executionStats" : {                
                "nReturned" : 154,
                "executionTimeMillis" : 1,
                "totalKeysExamined" : 154,
                "totalDocsExamined" : 154,
                "executionStages" : {
                        "stage" : "FETCH",
                        "nReturned" : 154,                        
                        "inputStage" : {
                                "stage" : "IXSCAN",
                                "nReturned" : 154,
                                "executionTimeMillisEstimate" : 0,                                
                                "indexName" : "borough_1_cuisine_1",

与没有索引的国家相比,我们肯定更好。

上述索引可以帮助我们对自治市镇财产进行过滤吗? 我们来试试如下:

db.restaurants.explain(true).find({"borough" : "Manhattan"})

是的,这绝对有帮助。 返回的文件总数为10259,也是扫描文件的数量。 查询计划显示复合索引用于加速查询执行。

关于美食领域的查询怎么样? 让我们来看看:

db.restaurants.explain(true).find({"cuisine" : "Thai"})

不,我们的复合指数根本没有帮助:

"winningPlan" : {
                        "stage" : "COLLSCAN",

...

 "executionStats" : {
                "executionSuccess" : true,
                "nReturned" : 288,
                "executionTimeMillis" : 13,
                "totalKeysExamined" : 0,
                "totalDocsExamined" : 25362,
                "executionStages" : {
                        "stage" : "COLLSCAN",
                        "filter" : {
                                "cuisine" : {
                                        "$eq" : "Thai"
                                }
                        },
                        "nReturned" : 288,

必须扫描集合中的所有文档。

这是合乎逻辑的,如果你考虑的话。 假设我们有来自所有英语国家的电话簿,一个用于加拿大,一个用于美国等。根据维基百科,有67个主权国家和27个符合这一标准的实体,所以我们有94本电话簿。 如果我们想找到所有居住在英国的姓Jones的人,那么我们可以咨询英国电话簿,忽略其余的。 但是,如果我们想找到所有姓Jones的人,那么我们必须扫描所有94本电话簿,收集所有相关的“文件”。

电话簿是按照该顺序的国家和姓氏的复合指数。 上述分析表明,在评估特定搜索的复合指数的可用性时,我们必须从左到右。 复合索引的第一个成员是主索引关键字,然后是次要密钥,其次是大专等。 如果我们在A,B和C上有一个复合索引,那么以下查询将使用索引:

  • 在A上过滤

  • 在A和B上过滤

  • 在A,B和C上进行过滤

其他过滤器,例如B或B和C上的过滤器将需要扫描集合中的所有文档。

我们将在下一篇文章中查看索引数组。

阿里云服务器,每月低至7.8元,项目演示即建站必备,比腾讯云更便宜,并且不需学生认证,从此链接购买有效: 去购买


版权声明:本站所有教程均为本站原创或翻译,转载请注明出处,请尊重他人劳动果实。请记住本站地址:www.yuanjiaocheng.net (猿教程) 作者:卿文刚
本文标题: C#环境
本文地址:http://www.yuanjiaocheng.net/CsharpMongo/32.html