monodb4.4 index《一》
  nQkVcpdWfLDr 2023年11月02日 29 0

1.索引简介

(1).准备基础数据
for (i=0;i<1000000; i++){
  db.users.insertOne({"i":i,username:"user"+i,age:Math.floor(Math.random()*120),created:new Date()})
}
(2).然后随机查找一个用户
wang> db.users.find({"username": "user101"}).explain("executionStats")
{
        "queryPlanner" : {
                "plannerVersion" : 1,
                "namespace" : "wang.users",
                "indexFilterSet" : false,
                "parsedQuery" : {
                        "username" : {
                                "$eq" : "user101"
                        }
                },
                "winningPlan" : {
                        "stage" : "COLLSCAN",
                        "filter" : {
                                "username" : {
                                        "$eq" : "user101"
                                }
                        },
                        "direction" : "forward"
                },
                "rejectedPlans" : [ ]
        },
        "executionStats" : {
                "executionSuccess" : true,
                "nReturned" : 1,
                "executionTimeMillis" : 848,
                "totalKeysExamined" : 0,
                "totalDocsExamined" : 1000000,
                "executionStages" : {
                        "stage" : "COLLSCAN",
                        "filter" : {
                                "username" : {
                                        "$eq" : "user101"
                                }
                        },
                        "nReturned" : 1,
                        "executionTimeMillisEstimate" : 106,
                        "works" : 1000002,
                        "advanced" : 1,
                        "needTime" : 1000000,
                        "needYield" : 0,
                        "saveState" : 1000,
                        "restoreState" : 1000,
                        "isEOF" : 1,
                        "direction" : "forward",
                        "docsExamined" : 1000000
                }
        },
        "serverInfo" : {
                "host" : "localhost.localdomain",
                "port" : 27017,
                "version" : "4.4.0",
                "gitVersion" : "563487e100c4215e2dce98d0af2a6a5a2d67c5cf"
        },
        "ok" : 1
}
wang> 

其中重点关注executionStats的以下参数

totalDocsExamined   已扫描的文档总数
executionTimeMillis 执行该操作所需的毫秒数
nReturned           返回的文档数
totalKeysExamined   显示0表示此查询未使用索引
(3).创建索引
db.users.createIndex({"username" : 1})

如果要查询索引的创建进度,可以使用以下命令

db.currentOp()

此时再次进行上面的查询(关注标红部分,增加索引后性能提升很大):

wang> db.users.find({"username": "user101"}).explain("executionStats")
{
        "queryPlanner" : {
                "plannerVersion" : 1,
                "namespace" : "wang.users",
                "indexFilterSet" : false,
                "parsedQuery" : {
                        "username" : {
                                "$eq" : "user101"
                        }
                },
                "winningPlan" : {
                        "stage" : "FETCH",
                        "inputStage" : {
                                "stage" : "IXSCAN",
                                "keyPattern" : {
                                        "username" : 1
                                },
                                "indexName" : "username_1",
                                "isMultiKey" : false,
                                "multiKeyPaths" : {
                                        "username" : [ ]
                                },
                                "isUnique" : false,
                                "isSparse" : false,
                                "isPartial" : false,
                                "indexVersion" : 2,
                                "direction" : "forward",
                                "indexBounds" : {
                                        "username" : [
                                                "[\"user101\", \"user101\"]"
                                        ]
                                }
                        }
                },
                "rejectedPlans" : [ ]
        },
        "executionStats" : {
                "executionSuccess" : true,
                "nReturned" : 1,
                "executionTimeMillis" : 57,
                "totalKeysExamined" : 1,
                "totalDocsExamined" : 1,
                "executionStages" : {
                        "stage" : "FETCH",
                        "nReturned" : 1,
                        "executionTimeMillisEstimate" : 10,
                        "works" : 2,
                        "advanced" : 1,
                        "needTime" : 0,
                        "needYield" : 0,
                        "saveState" : 0,
                        "restoreState" : 0,
                        "isEOF" : 1,
                        "docsExamined" : 1,
                        "alreadyHasObj" : 0,
                        "inputStage" : {
                                "stage" : "IXSCAN",
                                "nReturned" : 1,
                                "executionTimeMillisEstimate" : 10,
                                "works" : 2,
                                "advanced" : 1,
                                "needTime" : 0,
                                "needYield" : 0,
                                "saveState" : 0,
                                "restoreState" : 0,
                                "isEOF" : 1,
                                "keyPattern" : {
                                        "username" : 1
                                },
                                "indexName" : "username_1",
                                "isMultiKey" : false,
                                "multiKeyPaths" : {
                                        "username" : [ ]
                                },
                                "isUnique" : false,
                                "isSparse" : false,
                                "isPartial" : false,
                                "indexVersion" : 2,
                                "direction" : "forward",
                                "indexBounds" : {
                                        "username" : [
                                                "[\"user101\", \"user101\"]"
                                        ]
                                },
                                "keysExamined" : 1,
                                "seeks" : 1,
                                "dupsTested" : 0,
                                "dupsDropped" : 0
                        }
                }
        },
        "serverInfo" : {
                "host" : "localhost.localdomain",
                "port" : 27017,
                "version" : "4.4.0",
                "gitVersion" : "563487e100c4215e2dce98d0af2a6a5a2d67c5cf"
        },
        "ok" : 1
}
wang> 

2.复合索引(Compound Indexes)

复合索引就是建立在一个或多个字段上的索引

db.users.createIndex({"age" : 1, "username" : 1})

mongodb对这个索引的使用方式取决于查询的类型,下面是三种主要的方式。

(1).方式一
db.users.find({age:21}).sort({username:-1})

这个查询中第一个字段是等值查询,第二个字段已经在索引中了,查询结果已经是有序的了,所以逆序便利索引即可,查看执行计划

wang> db.users.find({age:21}).sort({username:-1}).explain("executionStats")
{
        "queryPlanner" : {
                "plannerVersion" : 1,
                "namespace" : "wang.users",
                "indexFilterSet" : false,
                "parsedQuery" : {
                        "age" : {
                                "$eq" : 21
                        }
                },
                "winningPlan" : {
                        "stage" : "FETCH",
                        "inputStage" : {
                                "stage" : "IXSCAN",
                                "keyPattern" : {
                                        "age" : 1,
                                        "username" : 1
                                },
                                "indexName" : "age_1_username_1",
                                "isMultiKey" : false,
                                "multiKeyPaths" : {
                                        "age" : [ ],
                                        "username" : [ ]
                                },
                                "isUnique" : false,
                                "isSparse" : false,
                                "isPartial" : false,
                                "indexVersion" : 2,
                                "direction" : "backward",
                                "indexBounds" : {
                                        "age" : [
                                                "[21.0, 21.0]"
                                        ],
                                        "username" : [
                                                "[MaxKey, MinKey]"
                                        ]
                                }
                        }
                },
                "rejectedPlans" : [ ]
        },
        "executionStats" : {
                "executionSuccess" : true,
                "nReturned" : 8336,
                "executionTimeMillis" : 47,
                "totalKeysExamined" : 8336,
                "totalDocsExamined" : 8336,
                "executionStages" : {
                        "stage" : "FETCH",
                        "nReturned" : 8336,
                        "executionTimeMillisEstimate" : 14,
                        "works" : 8337,
                        "advanced" : 8336,
                        "needTime" : 0,
                        "needYield" : 0,
                        "saveState" : 8,
                        "restoreState" : 8,
                        "isEOF" : 1,
                        "docsExamined" : 8336,
                        "alreadyHasObj" : 0,
                        "inputStage" : {
                                "stage" : "IXSCAN",
                                "nReturned" : 8336,
                                "executionTimeMillisEstimate" : 0,
                                "works" : 8337,
                                "advanced" : 8336,
                                "needTime" : 0,
                                "needYield" : 0,
                                "saveState" : 8,
                                "restoreState" : 8,
                                "isEOF" : 1,
                                "keyPattern" : {
                                        "age" : 1,
                                        "username" : 1
                                },
                                "indexName" : "age_1_username_1",
                                "isMultiKey" : false,
                                "multiKeyPaths" : {
                                        "age" : [ ],
                                        "username" : [ ]
                                },
                                "isUnique" : false,
                                "isSparse" : false,
                                "isPartial" : false,
                                "indexVersion" : 2,
                                "direction" : "backward",
                                "indexBounds" : {
                                        "age" : [
                                                "[21.0, 21.0]"
                                        ],
                                        "username" : [
                                                "[MaxKey, MinKey]"
                                        ]
                                },
                                "keysExamined" : 8336,
                                "seeks" : 1,
                                "dupsTested" : 0,
                                "dupsDropped" : 0
                        }
                }
        },
        "serverInfo" : {
                "host" : "localhost.localdomain",
                "port" : 27017,
                "version" : "4.4.0",
                "gitVersion" : "563487e100c4215e2dce98d0af2a6a5a2d67c5cf"
        },
        "ok" : 1
}
wang> 

这种查询是非常高效的,mongodb能够直接定位到正确的年龄,而且不需要对结果进行排序(因为只需要对数据进行逆序遍历就可以得到正确的顺序了)。

注意。排序的方向并不重要,mongodb可以在任意方向上对索引进行遍历。

(2).方式二
db.users.find({"age" : {"$gte" : 21, "$lte" : 30}})

这是一个多值查询,用于查找匹配多个值的文档(在此情况下,年龄在21至30岁之间)。 这种特定类型的查询有时也称为范围查询。 MongoDB将使用索引中的第一个键age返回匹配的文档

wang> db.users.find({"age" : {"$gte" : 21, "$lte" : 30}}).explain("executionStats")
{
        "queryPlanner" : {
                "plannerVersion" : 1,
                "namespace" : "wang.users",
                "indexFilterSet" : false,
                "parsedQuery" : {
                        "$and" : [
                                {
                                        "age" : {
                                                "$lte" : 30
                                        }
                                },
                                {
                                        "age" : {
                                                "$gte" : 21
                                        }
                                }
                        ]
                },
                "winningPlan" : {
                        "stage" : "FETCH",
                        "inputStage" : {
                                "stage" : "IXSCAN",
                                "keyPattern" : {
                                        "age" : 1,
                                        "username" : 1
                                },
                                "indexName" : "age_1_username_1",
                                "isMultiKey" : false,
                                "multiKeyPaths" : {
                                        "age" : [ ],
                                        "username" : [ ]
                                },
                                "isUnique" : false,
                                "isSparse" : false,
                                "isPartial" : false,
                                "indexVersion" : 2,
                                "direction" : "forward",
                                "indexBounds" : {
                                        "age" : [
                                                "[21.0, 30.0]"
                                        ],
                                        "username" : [
                                                "[MinKey, MaxKey]"
                                        ]
                                }
                        }
                },
                "rejectedPlans" : [ ]
        },
        "executionStats" : {
                "executionSuccess" : true,
                "nReturned" : 83522,
                "executionTimeMillis" : 333,
                "totalKeysExamined" : 83522,
                "totalDocsExamined" : 83522,
                "executionStages" : {
                        "stage" : "FETCH",
                        "nReturned" : 83522,
                        "executionTimeMillisEstimate" : 73,
                        "works" : 83523,
                        "advanced" : 83522,
                        "needTime" : 0,
                        "needYield" : 0,
                        "saveState" : 83,
                        "restoreState" : 83,
                        "isEOF" : 1,
                        "docsExamined" : 83522,
                        "alreadyHasObj" : 0,
                        "inputStage" : {
                                "stage" : "IXSCAN",
                                "nReturned" : 83522,
                                "executionTimeMillisEstimate" : 32,
                                "works" : 83523,
                                "advanced" : 83522,
                                "needTime" : 0,
                                "needYield" : 0,
                                "saveState" : 83,
                                "restoreState" : 83,
                                "isEOF" : 1,
                                "keyPattern" : {
                                        "age" : 1,
                                        "username" : 1
                                },
                                "indexName" : "age_1_username_1",
                                "isMultiKey" : false,
                                "multiKeyPaths" : {
                                        "age" : [ ],
                                        "username" : [ ]
                                },
                                "isUnique" : false,
                                "isSparse" : false,
                                "isPartial" : false,
                                "indexVersion" : 2,
                                "direction" : "forward",
                                "indexBounds" : {
                                        "age" : [
                                                "[21.0, 30.0]"
                                        ],
                                        "username" : [
                                                "[MinKey, MaxKey]"
                                        ]
                                },
                                "keysExamined" : 83522,
                                "seeks" : 1,
                                "dupsTested" : 0,
                                "dupsDropped" : 0
                        }
                }
        },
        "serverInfo" : {
                "host" : "localhost.localdomain",
                "port" : 27017,
                "version" : "4.4.0",
                "gitVersion" : "563487e100c4215e2dce98d0af2a6a5a2d67c5cf"
        },
        "ok" : 1
}
wang> 
(3).方式三
db.users.find({"age" : {"$gte" : 21, "$lte" :30}}).sort({"username" : 1})

由于第一个字段使用了范围查询,所以第二哥字段无法使用索引,所以必须在内存中进行排序,因此这种查询不如第一个高效

wang> db.users.find({"age" : {"$gte" : 21, "$lte" :30}}).sort({"username" : 1}).explain("executionStats")
{
        "queryPlanner" : {
                "plannerVersion" : 1,
                "namespace" : "wang.users",
                "indexFilterSet" : false,
                "parsedQuery" : {
                        "$and" : [
                                {
                                        "age" : {
                                                "$lte" : 30
                                        }
                                },
                                {
                                        "age" : {
                                                "$gte" : 21
                                        }
                                }
                        ]
                },
                "winningPlan" : {
                        "stage" : "FETCH",
                        "filter" : {
                                "$and" : [
                                        {
                                                "age" : {
                                                        "$lte" : 30
                                                }
                                        },
                                        {
                                                "age" : {
                                                        "$gte" : 21
                                                }
                                        }
                                ]
                        },
                        "inputStage" : {
                                "stage" : "IXSCAN",
                                "keyPattern" : {
                                        "username" : 1
                                },
                                "indexName" : "username_1",
                                "isMultiKey" : false,
                                "multiKeyPaths" : {
                                        "username" : [ ]
                                },
                                "isUnique" : false,
                                "isSparse" : false,
                                "isPartial" : false,
                                "indexVersion" : 2,
                                "direction" : "forward",
                                "indexBounds" : {
                                        "username" : [
                                                "[MinKey, MaxKey]"
                                        ]
                                }
                        }
                },
                "rejectedPlans" : [
                        {
                                "stage" : "FETCH",
                                "inputStage" : {
                                        "stage" : "SORT",
                                        "sortPattern" : {
                                                "username" : 1
                                        },
                                        "memLimit" : 104857600,
                                        "type" : "default",
                                        "inputStage" : {
                                                "stage" : "IXSCAN",
                                                "keyPattern" : {
                                                        "age" : 1,
                                                        "username" : 1
                                                },
                                                "indexName" : "age_1_username_1",
                                                "isMultiKey" : false,
                                                "multiKeyPaths" : {
                                                        "age" : [ ],
                                                        "username" : [ ]
                                                },
                                                "isUnique" : false,
                                                "isSparse" : false,
                                                "isPartial" : false,
                                                "indexVersion" : 2,
                                                "direction" : "forward",
                                                "indexBounds" : {
                                                        "age" : [
                                                                "[21.0, 30.0]"
                                                        ],
                                                        "username" : [
                                                                "[MinKey, MaxKey]"
                                                        ]
                                                }
                                        }
                                }
                        }
                ]
        },
        "executionStats" : {
                "executionSuccess" : true,
                "nReturned" : 83522,
                "executionTimeMillis" : 3292,
                "totalKeysExamined" : 1000000,
                "totalDocsExamined" : 1000000,
                "executionStages" : {
                        "stage" : "FETCH",
                        "filter" : {
                                "$and" : [
                                        {
                                                "age" : {
                                                        "$lte" : 30
                                                }
                                        },
                                        {
                                                "age" : {
                                                        "$gte" : 21
                                                }
                                        }
                                ]
                        },
                        "nReturned" : 83522,
                        "executionTimeMillisEstimate" : 765,
                        "works" : 1000001,
                        "advanced" : 83522,
                        "needTime" : 916478,
                        "needYield" : 0,
                        "saveState" : 1001,
                        "restoreState" : 1001,
                        "isEOF" : 1,
                        "docsExamined" : 1000000,
                        "alreadyHasObj" : 0,
                        "inputStage" : {
                                "stage" : "IXSCAN",
                                "nReturned" : 1000000,
                                "executionTimeMillisEstimate" : 315,
                                "works" : 1000001,
                                "advanced" : 1000000,
                                "needTime" : 0,
                                "needYield" : 0,
                                "saveState" : 1001,
                                "restoreState" : 1001,
                                "isEOF" : 1,
                                "keyPattern" : {
                                        "username" : 1
                                },
                                "indexName" : "username_1",
                                "isMultiKey" : false,
                                "multiKeyPaths" : {
                                        "username" : [ ]
                                },
                                "isUnique" : false,
                                "isSparse" : false,
                                "isPartial" : false,
                                "indexVersion" : 2,
                                "direction" : "forward",
                                "indexBounds" : {
                                        "username" : [
                                                "[MinKey, MaxKey]"
                                        ]
                                },
                                "keysExamined" : 1000000,
                                "seeks" : 1,
                                "dupsTested" : 0,
                                "dupsDropped" : 0
                        }
                }
        },
        "serverInfo" : {
                "host" : "localhost.localdomain",
                "port" : 27017,
                "version" : "4.4.0",
                "gitVersion" : "563487e100c4215e2dce98d0af2a6a5a2d67c5cf"
        },
        "ok" : 1
}
wang> 

如果您的结果超过32MB结果MongoDB只会出错,拒绝对大量数据进行排序:

Error: error: {
  "ok" : 0,
  "errmsg" : "Executor error during find command: OperationFailed:
Sort operation used more than the maximum 33554432 bytes of RAM. Add
an index, or specify a smaller limit.",
  "code" : 96,
  "codeName" : "OperationFailed"
}

如果使用 {"username" : 1, "age" : 1} 索引会得到很好的效果。

设计复合索引时:

等值查询的键应该首先出现。

用于排序的键应该出现在多值字段之前。

多值过滤器的键应该出现在最后。

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  lG7RE7vNF4mc   2023年11月13日   30   0   0 3d权重字段
  wpWn7yzs0oKF   2023年11月13日   38   0   0 数据库字段SQL
  nQkVcpdWfLDr   2023年11月13日   36   0   0 数据2d字段
nQkVcpdWfLDr