示例:
db.getCollection('file').find({});
结果:
/* 1 */
{
"_id" : ObjectId("5e7179de0af8595d0bbe243f"),
"fileName" : "test.apk",
"fileCTime" : NumberLong(1584495748123),
"version" : "1"
}
/* 2 */
{
"_id" : ObjectId("5e7dc423e20bc4b7fa6c205a"),
"fileName" : "b.html",
"version" : "2"
}
/* 3 */
{
"_id" : ObjectId("5e7dc423e20bc4b7fa6c205b"),
"fileName" : "b.html",
"version" : "3"
}
按照fileName升序,然后按照version降序
db.getCollection('file').find({}).sort({fileName:1,version:-1})
结果:
/* 1 */
{
"_id" : ObjectId("5e7dc423e20bc4b7fa6c205a"),
"fileName" : "b.html",
"version" : "2 "
}
/* 2 */
{
"_id" : ObjectId("5e7dc423e20bc4b7fa6c205b"),
"fileName" : " b.html",
"version" : "3"
}
/* 3 */
{
"_id" : ObjectId("5e7179de0af8595d0bbe243f"),
"fileName" : "test.apk",
"fileCTime" : NumberLong(1584495748123),
"version" : "1"
}
Mongo慢查询优化
监控
mongodb可以通过profile来监控查询,查出耗时查询,然后进行优化。
profile常用命令:
db.getProfilingLevel();//查看当前是否开启profile功能用命令,返回level等级,值为0-关闭、1-慢命令、2-全部
db.setProfilingLevel(level);//开启profile功能
level为1的时候,慢命令默认值为100ms,更改为db.setProfilingLevel(level,slowms)
如db.setProfilingLevel(1,50);//更改慢命令值为50ms
db.system.profile.find() //当前的监控日志。
db.system.profile.find({millis:{$gt:500}});//返回查询时间在500毫秒以上的查询命令。
{
"op" : "query",
"ns" : "ones.file",//慢日志是所在库和集合
"command" : { //具体查询命令
"find" : "file",
"filter" : {
"qbuildCid" : 449557
},
"projection" : {},
"limit" : 1,
"singleBatch" : true,
"$db" : "ones",
"lsid" : {
"id" : UUID("a9086c77-b0ae-4de1-b0d2-9db19a455762")
}
},
"keysExamined" : 0,
"docsExamined" : 221258,//此次查询遍历文档个数
"cursorExhausted" : true,
"numYield" : 1728,
"nreturned" : 1,
"locks" : {
"Global" : {
"acquireCount" : {
"r" : NumberLong(1731)
}
},
"Database" : {
"acquireCount" : {
"r" : NumberLong(1729)
}
},
"Collection" : {
"acquireCount" : {
"r" : NumberLong(1729)
}
}
},
"storage" : {},
"responseLength" : 712,
"protocol" : "op_msg",
"millis" : 220,//查询耗时
"planSummary" : "COLLSCAN",
"execStats" : {
"stage" : "LIMIT",
"nReturned" : 1,
"executionTimeMillisEstimate" : 10,
"works" : 221260,
"advanced" : 1,
"needTime" : 221258,
"needYield" : 0,
"saveState" : 1728,
"restoreState" : 1728,
"isEOF" : 1,
"invalidates" : 0,
"limitAmount" : 1,
"inputStage" : {
"stage" : "COLLSCAN",
"filter" : {
"qbuildCid" : {
"$eq" : 449557
}
},
"nReturned" : 1,
"executionTimeMillisEstimate" : 10,
"works" : 221259,
"advanced" : 1,
"needTime" : 221258,
"needYield" : 0,
"saveState" : 1728,
"restoreState" : 1728,
"isEOF" : 0,
"invalidates" : 0,
"direction" : "forward",
"docsExamined" : 221258
}
},
"ts" : ISODate("2020-05-27T10:50:15.394Z"),//命令执行时间
"client" : "10.10.10.10",
"allUsers" : [
{
"user" : "mongo",
"db" : "admin"
}
],
"user" : "mongo@admin"
}
millis为查询耗时,如果发现时间比较长,那么就需要作优化。
docsExamined代表查询遍历文档数,如果该值很大,或者接近记录总数,那么可能没有用到索引查询。
索引
如果发现查询的时间较长,那么可能需要为待查询的字段建立索引。
索引的原理是通过建立指定字段的B-Tree,通过搜索B-Tree来查找对应document的地址。如果需要查询超过一半的集合数据,那直接遍历效率反而会更高,因为省去了搜索B-Tree的过程。
结果集在原集合中所占的比例越大,查询效率越慢。因为使用索引需要进行两次查找:一次查找索引条目,一次根据索引指针去查找相应的文档。而全表扫描只需要进行一次查询。在最坏的情况,使用索引进行查找次数会是全表扫描的两倍。效率会明显比全表扫描低。例如,在文件表中,我们拥有一个"type"列索引,如果在"type"列中,android占了50%,如果现在要查询一个类型为android,文件名为“test.apk"的文件,我们则需要在表的50%的数据中查询,这样有索引的性能会降低。
而相反在提取较小的子数据集时,索引就非常有效,这就是我们为什么会使用分页。
索引设计原则
**8.控制字段数:**如果你设计的索引例如含有7、8个字段通常需要考虑设计是否合理
Explain查询计划
命令:
>db.getCollection(‘file’).find({qbuildId:441557}).explain()
Explain结果
explain 结果将查询计划以阶段树的形式呈现。
每个阶段将其结果(文档或索引键)传递给父节点。
中间节点操纵由子节点产生的文档或索引键。
根节点是MongoDB从中派生结果集的最后阶段。
在看查询结果的阶段树的时候一定一定是从最里层一层一层往外看的,不是直接顺着读下来的。
在查询计划中出现了很多stage,下面列举的经常出现的stage以及他的含义:
**TEXT:**使用全文索引进行查询时候的stage返回通过这些信息就能判断查询时如何执行的了
其他
如果数据文件大于系统内存,查询速度会下降几个数量级,因为mongodb是内存数据库。1000万数据的时候没有索引情况下查询可能会几秒钟甚至更久。
另外一点是数据索引如果大于内存,速度也会下降很多。而且对于多条件查询,如果你查询的顺序和索引顺序不同,也不能使用索引。
如果你使用了replica set,这个会影响写入速度的,三个replica set,速度会降低到三分之一。
学习安排上
作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助。【保证100%免费】
视频文档获取方式:
这份文档和视频资料,对于想从事【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!以上均可以分享,点下方小卡片即可自行领取。