目录
一、查询分析器
1. 启用查询分析器
2. 禁用查询分析器
3. 查找慢查询
4. 增大分析器集合的大小
二、explain
三、使用索引优化查询
1. 管理索引
2. 索引选择三步法
3. 指定索引选项
4. 使用hint()
5. 使用索引过滤器
一、查询分析器
1. 启用查询分析器
> use test;
switched to db test
> db.setProfilingLevel(1);
{ "was" : 0, "slowms" : 100, "sampleRate" : 1, "ok" : 1 }
2. 禁用查询分析器
> use test;
switched to db test
> db.setProfilingLevel(0);
{ "was" : 1, "slowms" : 100, "sampleRate" : 1, "ok" : 1 }
>
# 只记录执行超过半秒钟的查询:
> use test;
switched to db test
> db.setProfilingLevel(1,500);
{ "was" : 1, "slowms" : 500, "sampleRate" : 1, "ok" : 1 }
对于分析级别1,可以提供以毫秒为单位的最大查询执行时间。如果查询的执行时间超过该设置,它将被分析,然后记录下来;否则,它将被忽略。这种方式提供了与MySQL慢查询日志相同的功能。若将分析级别设置为2,可为所有查询启用分析器:
> use test;
switched to db test
> db.setProfilingLevel(2);
{ "was" : 2, "slowms" : 100, "sampleRate" : 1, "ok" : 1 }
3. 查找慢查询
db.system.profile.find();
每条记录返回的字段含义和作用:
op:操作类型,可以是query、insert、update、command或delete。
query:正在运行的查询。
ns:查询所在的完整命名空间。
ntoreturn:返回文档的数目。
nscanned:为返回该文档而扫描的索引条目数目。
ntoskip:被忽略的文档数目。
keyUpdates:该查询更新的索引键数目。
numYields:该查询为其它查询让出锁的次数。
lockStats:数据库花费在获取读写锁上的毫秒数。
nreturned:返回文档的数目。
responseLength:响应的字节长度。
millis:执行查询所花费的毫秒数。
ts:以UTC格式显示查询执行时的时间戳。
client:运行该查询的客户端连接信息。
user:运行该操作的用户。
查询所有执行时间长于10毫秒的查询,然后按执行时间对结果进行降序排序:
db.system.profile.find({millis:{$gt:10}}).sort({millis:-1});
4. 增大分析器集合的大小
use test;
db.setProfilingLevel(0);
db.system.profile.drop();
db.createCollection( "system.profile", { capped: true, size: 50 * 1024 * 1024 } );
db.setProfilingLevel(2);
二、explain
> db.products.find().explain(true)
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "test.products",
"indexFilterSet" : false,
"parsedQuery" : {
},
"winningPlan" : {
"stage" : "COLLSCAN",
"direction" : "forward"
},
"rejectedPlans" : [ ]
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 3,
"executionTimeMillis" : 0,
"totalKeysExamined" : 0,
"totalDocsExamined" : 3,
"executionStages" : {
"stage" : "COLLSCAN",
"nReturned" : 3,
"executionTimeMillisEstimate" : 0,
"works" : 5,
"advanced" : 3,
"needTime" : 1,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"direction" : "forward",
"docsExamined" : 3
},
"allPlansExecution" : [ ]
},
"serverInfo" : {
"host" : "hdp4",
"port" : 27017,
"version" : "4.0.2",
"gitVersion" : "fc1573ba18aee42f97a3bb13b67af7d837826b47"
},
"ok" : 1
}
>
explain()以下字段:
queryPlanner:执行查询的细节,包括计划的细节。
queryPlanner.indexFilterSet:表明是否使用索引过滤器来实现这个查询。
queryPlanner.parsedQuery:正在运行的查询。这是查询修改后的形式,显示了如何在内部评估它。
queryPlanner.winningPlan:被选中来执行查询的计划。
executionStats.keysExamined:表示为找到查询中的所有对象二扫描的索引条目数。
executionStats.docsExamined:显示实际扫描的对象数量,而不仅是它们的索引条目。
executionStats.nReturned:显示游标上的条目数量(即返回的条目数量)。
executionStages:提供执行计划的细节。
serverInfo:执行该查询的服务器。
indexFilterSet表示没有使用索引;COLLSCAN表示集合扫描。如果docsExamined显著高于nReturned,那么查询可能需要添加索引。
三、使用索引优化查询
1. 管理索引
MongoDB的索引用于查询(find、findOne)和排序。如果倾向于在集合中大量使用排序,那么应该根据排序的需求添加索引。
索引最好用在主要为读访问的集合中。如果集合中有过多的索引,它们有可能会对写操作的性能造成负面影响。
目前每个集合最多可以拥有64个索引。
一个查询中只会使用一个索引,所以添加许多小索引通常并不会改善查询性能。复合索引提供了一种减少集合中索引数目的方法,它允许将多个字段结合在一起创建一个索引,所以应该尽量使用符合索引。
除非数据项的列表和排序与索引结构匹配,否则排序不利用复合索引。
(1)显示索引
db.posts.getIndexes();
(2)创建简单索引
db.posts.createIndex({Tags:1});
db.posts.createIndex({Tags:-1});
db.posts.createIndex({"comments.count":1});
# 查询多值索引
db.posts.find({Tags:{$all: ['sailor', 'moon']}});
(3)创建复合索引
db.articles.find({author:{name: 'joe', email: 'joe@blogger.com'}));
db.posts.createIndex({"author.name":1, "author.email":1});
(4)删除索引
# 删除一个集合上的所有索引
db.posts.dropIndexes();
# 删除单个索引(对应于createIndex()函数创建索引的语法)
db.posts.dropIndex({"author.name":1, "author.email":1});
(5)重建索引
# 重建一个集合上的所有索引,nIndexesWas与nIndexes应该相同
db.posts.reIndex();
2. 索引选择三步法
(1)相等测试:按任意顺序把所有相等测试的字段添加到复合索引中。
(2)排序字段:(只有存在多个排序字段,升序/降序才重要)在索引中添加排序字段,其顺序和方向与查询的排序相同。
(3)范围过滤器:首先,为基数最低的字段添加范围过滤器(集合中不同的值最少),接着添加基数次低的范围过滤器,直到基数最高的范围过滤器为止。
如果相等测试或范围过滤器字段没有选择性,就可以省略它们,以减少索引的大小。经验法则是,如果字段没有过滤掉集合中至少90%的文档,就最好在索引中省略它。如果集合上有几个索引,就可能需要提示MongoDB使用正确的索引。
3. 指定索引选项
(1)后台创建索引
db.posts.createIndex({author:1}, {background:true});
# 终止索引进程
db.currentOp();
db.killOp(<opid>);
(2)创建唯一索引
db.posts.createIndex({author:1}, {unique:true});
(3)创建稀疏索引
db.posts.createIndex({author:1}, {sparse:true});
(4)创建部分(条件)索引
db.restaurants.createIndex(
{ name: 1 },
{ partialFilterExpression: { cost: { $gt: 10 } } } )
(5)TTL索引
db.comments.createIndex({ts:1},{ expireAfterSeconds: 2419200});
date = new Date(new Date().getTime()-2419200000);
db.comments.insert({ "author" : "test", "body" : "foo", "ts" : date, "tags" : [] });
db.comments.find();
# 等待一分钟,文档将被自动删除
(6)文本索引
db.posts.createIndex( { body: "text" } );
db.posts.find({ "$text" : { $search: "MongoDB" } });
db.posts.find({ "$text" : { $search: "MongoDB", $caseSensitive : true } });
4. 使用hint()
db.posts.createIndex({"author.name":1, "author.email":1});
db.posts.find({author:{name:'joe', email: 'joe@mongodb.com'}}).hint({"author.name":1,"author.email":1});
# 不使用任何索引
db.posts.find({author:{name: 'joe', email: 'joe@mongodb.com'}}).hint({$natural:1});
5. 使用索引过滤器
db.runCommand(
{
planCacheSetFilter: "stuff",
query: {letter : {$gt : "B"}, shape : "circle"},
sort: {number:1},
projection: { },
indexes: [ { letter:1, shape:1} ]
}
);
db.runCommand( { planCacheListFilters:"stuff"});
db.runCommand(
{
planCacheClearFilters : "stuff",
query: {letter : {$gt : "B"}, shape : "circle"},
sort: {number:1},
projection: { },
indexes: [ { letter:1, shape:1} ]
}
);
————————————————
版权声明:本文为CSDN博主「wzy0623」的原创文章
原文链接:https://blog.csdn.net/wzy0623/java/article/details/83060759