慢查询分析
db.setProfilingLevel(n,m),n的取值可选0,1,2
示例:
db.setProfilingLevel(1,3)
db.system.profile.find().sort({millis:-1}).limit(3)
什么是索引?
索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。索引的作用相当于图书的目录,可以根据目录中的页码快速找到所需的内容。索引目标是提高数据库的查询效率,没有索引的话,查询会进行全表扫描(scaneverydocumentinacollection),数据量大时严重降低了查询效率。默认情况下Mongo在一个集合(collection)创建时,自动地对集合的_id创建了唯一索引。
索引结构
MongoDB的索引结构为B树
B树非叶子节点也存了数据,查询效率不固定,最好的情况是O(1),在单次查询的情况下平均性能是优于B+树的。而MongoDB是被作为一个单一查询比较多,遍历数据比较少的一个定位。所以采用了B树。
那为什么不用单次性能更好的Hash结构呢?
因为虽然遍历数据的情况较少,但是对于遍历数据也需要有相对较好的性能支持。Hash这种性能表现较为极端的数据结构往往只能在简单、极端的场景下使用。
索引分类
MongoDB支持所有数据类型中的单个字段索引,并且可以在文档的任何字段定义。对于单个字段索引,索引键的排序顺序无关紧要,因为MongoDB可以在任一方向读取索引。
db.集合名.createIndex({"字段名":排序方式})
示例:
db.user.createIndex({"name":1})
创建后可以通过查询索引命令查看是否创建成功。
db.user.getIndexes()
设置unique为true。示例:
db.book.createIndex({title:1},{unique:true})
TTL索引是MongoDB中一种特殊的索引,可以支持文档在一定时间之后自动过期删除,目前TTL索引只能在单字段上建立,并且字段类型必须是日期类型。
db.集合名.createIndex({"日期字段":排序方式}, {expireAfterSeconds: 秒数})
示例:
db.user.createIndex({"bithday":1}, {expireAfterSeconds: 10})
创建过期索引后,有bithday字段的文档会在约10秒后自动删除。
通常我们需要在多个字段上进行搜索,如果是这种情况,可以考虑使用复合索引。复合索引支持基于多个字段的索引,这扩展了索引的概念并将它们扩展到索引中的更大域。
建立复合索引需要注意:字段顺序和索引方向。它也是遵循最左前缀原则。
db.集合名.createIndex( { "字段名1" : 排序方式, "字段名2" : 排序方式 } )
针对属性包含数组数据的情况,MongoDB支持针对数组中每一个element创建索引,支持Strings、numbers、nested documents。
示例:
//type是集合类型的数据,创建的就是多键索引 db.book.insert({title:"java",type:["技术","IT"]}) db.book.createIndex({type:1})
针对属性的哈希值进行索引查询,当要使用Hashed Index时,MongoDB能够自动计算hash值来进行查询。
db.集合.createIndex({"字段": "hashed"})
针对地理空间坐标数据创建索引。2dsphere索引:用于存储和查找球面上的点。
2d索引:用于存储和查找平面上的点。
db.集合名.ensureIndex({字段名:"2dsphere"})
示例:
//插入数据 db.company.insert({ loc:{type:"Point",coordinates:[116.482451,39.914176]}, name:"大望路", category:"Parks" }) //创建索引 db.company.ensureIndex({loc:"2dsphere"}) //查询范围内的数据 db.company.find({ "loc":{ "$geoWithin":{ "$center":[[116.482450,39.914176],0.05] } } }) //距离指定位置最近的2个点 db.company.aggregate([ { $geoNear: { near: { type: "Point", coordinates: [ 116.472451,39.814176] }, key:"loc", distanceField: "dist.calculated", spherical: true } }, { $limit: 2 } ])
索引管理
有时数据量大的时候,创建索引的动作是比较耗费时间的,这时后台运行就比较有用了。
db.COLLECTION_NAME.createIndex({"字段":排序方式}, {background: true});
db.COLLECTION_NAME.getIndexes()
db.COLLECTION_NAME.totalIndexSize()
db.COLLECTION_NAME.reIndex()
db.COLLECTION_NAME.dropIndex("INDEX-NAME") db.COLLECTION_NAME.dropIndexes() 注意: _id 对应的索引是删除不了的
Explain分析
explain()是一个查询分析的方法,它还可以接收不同的参数来查看更详细的查询计划。
简单示例:
db.user.find().explain() db.user.find({name:"test1"}).explain("executionStats")
参数介绍:
这么多返回值我们怎么分析呢?
首先我们先造点数据:
for(var i=0;i<100000;i++){ db.user.insert({ name:"test"+i, explectSalary:10+i }) }
查询耗时115
db.user.find({name:"test1"}).explain("allPlansExecution")
然后创建索引
db.user.createIndex({name:1})
再次查询,查看耗时变为了2。速度直线飙升。我们再对返回结果做一个分析:
{ "queryPlanner" : { "plannerVersion" : 1, "namespace" : "test.user", "indexFilterSet" : false, "parsedQuery" : { "name" : { "$eq" : "test1" } }, "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" : [ "[\"test1\", \"test1\"]" ] } } }, "rejectedPlans" : [ ] }, "executionStats" : { "executionSuccess" : true, "nReturned" : 2, "executionTimeMillis" : 2, "totalKeysExamined" : 2, "totalDocsExamined" : 2, "executionStages" : { "stage" : "FETCH", "nReturned" : 2, "executionTimeMillisEstimate" : 0, "works" : 3, "advanced" : 2, "needTime" : 0, "needYield" : 0, "saveState" : 0, "restoreState" : 0, "isEOF" : 1, "docsExamined" : 2, "alreadyHasObj" : 0, "inputStage" : { "stage" : "IXSCAN", "nReturned" : 2, "executionTimeMillisEstimate" : 0, "works" : 3, "advanced" : 2, "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" : [ "[\"test1\", \"test1\"]" ] }, "keysExamined" : 2, "seeks" : 1, "dupsTested" : 0, "dupsDropped" : 0 } }, "allPlansExecution" : [ ] }, "serverInfo" : { "host" : "10.0.3.15", "port" : 27017, "version" : "4.2.21", "gitVersion" : "b0aeed9445ff41af07449fa757e1f231bce990b3" }, "ok" : 1 }
折叠
重要参数介绍:
对于一个查询,我们最理想的状态是:nReturned=totalKeysExamined=totalDocsExamined
类型列举如下:
还有的是上面的组合
到此这篇关于MongoDB慢查询与索引的文章就介绍到这了,更多相关MongoDB慢查询与索引内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!