浅尝辄止MongoDB:优化

目录

一、查询分析器

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} ]
    }
);

 

©️2020 CSDN 皮肤主题: 深蓝海洋 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值