MongoDB优化

备注:
MongoDB 4.2 版本

一.查询分析器

1.1 启用查询分析器

> use test
switched to db test
> db.setProfilingLevel(1);
{ "was" : 0, "slowms" : 100, "sampleRate" : 1, "ok" : 1 }
> 

1.2 禁用查询分析器

> use test
switched to db test
> db.setProfilingLevel(0);
{ "was" : 1, "slowms" : 100, "sampleRate" : 1, "ok" : 1 }
> 

1.3 记录慢查询

-- 只记录执行超过半秒钟的查询
db.setProfilingLevel(1,500);
-- 所有查询启用分析器
db.setProfilingLevel(2);

测试记录:

> use test
switched to db test
> db.setProfilingLevel(1,500);
{ "was" : 0, "slowms" : 100, "sampleRate" : 1, "ok" : 1 }
> db.setProfilingLevel(2);
{ "was" : 1, "slowms" : 500, "sampleRate" : 1, "ok" : 1 }
> 
> 
> 
> db.setProfilingLevel(1,500);
{ "was" : 2, "slowms" : 500, "sampleRate" : 1, "ok" : 1 }
> 

1.4 查找慢查询

use test;
db.system.profile.find();
-- 查询所有执行时间长于10毫秒的查询,然后按执行时间对结果进行降序排序:
db.system.profile.find({millis:{$gt:10}}).sort({millis:-1});

每条记录返回的字段含义和作用:
op:操作类型,可以是query、insert、update、command或delete。
query:正在运行的查询。
ns:查询所在的完整命名空间。
ntoreturn:返回文档的数目。
nscanned:为返回该文档而扫描的索引条目数目。
ntoskip:被忽略的文档数目。
keyUpdates:该查询更新的索引键数目。
numYields:该查询为其它查询让出锁的次数。
lockStats:数据库花费在获取读写锁上的毫秒数。
nreturned:返回文档的数目。
responseLength:响应的字节长度。
millis:执行查询所花费的毫秒数。
ts:以UTC格式显示查询执行时的时间戳。
client:运行该查询的客户端连接信息。
user:运行该操作的用户。

图形化界面看起来更直关
image.png

1.5 增大分析器集合的大小

use test;
db.setProfilingLevel(0);
db.system.profile.drop();
db.createCollection( "system.profile", { capped: true, size: 50 * 1024 * 1024 } );
db.setProfilingLevel(2);

测试记录:

> use test;
switched to db test
> db.setProfilingLevel(0);
{ "was" : 1, "slowms" : 500, "sampleRate" : 1, "ok" : 1 }
> db.system.profile.drop();
true
> db.createCollection( "system.profile", { capped: true, size: 50 * 1024 * 1024 } );
{ "ok" : 1 }
> db.setProfilingLevel(2);
{ "was" : 0, "slowms" : 500, "sampleRate" : 1, "ok" : 1 }
> 

二.explain

> db.t2.find().explain(true)
{
        "queryPlanner" : {
                "plannerVersion" : 1,
                "namespace" : "test.t2",
                "indexFilterSet" : false,
                "parsedQuery" : {

                },
                "winningPlan" : {
                        "stage" : "COLLSCAN",
                        "direction" : "forward"
                },
                "rejectedPlans" : [ ]
        },
        "executionStats" : {
                "executionSuccess" : true,
                "nReturned" : 1000000,
                "executionTimeMillis" : 366,
                "totalKeysExamined" : 0,
                "totalDocsExamined" : 1000000,
                "executionStages" : {
                        "stage" : "COLLSCAN",
                        "nReturned" : 1000000,
                        "executionTimeMillisEstimate" : 0,
                        "works" : 1000002,
                        "advanced" : 1000000,
                        "needTime" : 1,
                        "needYield" : 0,
                        "saveState" : 7812,
                        "restoreState" : 7812,
                        "isEOF" : 1,
                        "direction" : "forward",
                        "docsExamined" : 1000000
                },
                "allPlansExecution" : [ ]
        },
        "serverInfo" : {
                "host" : "10-31-1-122",
                "port" : 27017,
                "version" : "4.2.10",
                "gitVersion" : "88276238fa97b47c0ef14362b343c5317ecbd739"
        },
        "ok" : 1
}
> 

explain()以下字段:

queryPlanner:执行查询的细节,包括计划的细节。
queryPlanner.indexFilterSet:表明是否使用索引过滤器来实现这个查询。
queryPlanner.parsedQuery:正在运行的查询。这是查询修改后的形式,显示了如何在内部评估它。
queryPlanner.winningPlan:被选中来执行查询的计划。
executionStats.keysExamined:表示为找到查询中的所有对象二扫描的索引条目数。
executionStats.docsExamined:显示实际扫描的对象数量,而不仅是它们的索引条目。
executionStats.nReturned:显示游标上的条目数量(即返回的条目数量)。
executionStages:提供执行计划的细节。
serverInfo:执行该查询的服务器。

indexFilterSet表示没有使用索引;COLLSCAN表示集合扫描。如果docsExamined显著高于nReturned,那么查询可能需要添加索引。

三.使用索引优化查询

3.1 管理索引

MongoDB的索引用于查询(find、findOne)和排序。如果倾向于在集合中大量使用排序,那么应该根据排序的需求添加索引。
索引最好用在主要为读访问的集合中。如果集合中有过多的索引,它们有可能会对写操作的性能造成负面影响。
目前每个集合最多可以拥有64个索引。
一个查询中只会使用一个索引,所以添加许多小索引通常并不会改善查询性能。复合索引提供了一种减少集合中索引数目的方法,它允许将多个字段结合在一起创建一个索引,所以应该尽量使用符合索引。
除非数据项的列表和排序与索引结构匹配,否则排序不利用复合索引。

MongoDB indexes use a B-tree data structure
这个现实MongoDB索引同关系型数据库一样,也是 B-tree索引

3.1.1 显示索引

> use test
switched to db test
> 
> db.t2.getIndexes()
[
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_",
                "ns" : "test.t2"
        }
]
> 

3.1.2 创建索引

创建索引语法:

-- 语法
db.collection.createIndex( <key and index type specification>, <options> )
-- 降序索引
db.collection.createIndex( { name: -1 } )
-- t2集合 id文档 创建索引
> db.t2.createIndex({id:1})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
}
> 
> db.t2.getIndexes()
[
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_",
                "ns" : "test.t2"
        },
        {
                "v" : 2,
                "key" : {
                        "id" : 1
                },
                "name" : "id_1",
                "ns" : "test.t2"
        }
]
> 

-- t2集合 name、date两个文档创建复合索引
> db.t2.getIndexes()
[
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_",
                "ns" : "test.t2"
        },
        {
                "v" : 2,
                "key" : {
                        "id" : 1
                },
                "name" : "id_1",
                "ns" : "test.t2"
        },
        {
                "v" : 2,
                "key" : {
                        "name" : 1,
                        "date" : 1
                },
                "name" : "联合索引",
                "ns" : "test.t2"
        }
]
> 

3.1.3 删除索引

# 删除一个集合上的所有索引
db.t2.dropIndexes();
# 删除单个索引(对应于createIndex()函数创建索引的语法)
db.t2.createIndex({name:1,date:1},{name : "联合索引"})
db.t2.dropIndex({name:1,date:1},{name : "联合索引"})

测试记录:

> db.t2.dropIndexes();
{
        "nIndexesWas" : 3,
        "msg" : "non-_id indexes dropped for collection",
        "ok" : 1
}
> db.t2.getIndexes()
[
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_",
                "ns" : "test.t2"
        }
]
> 
> db.t2.createIndex({name:1,date:1},{name : "联合索引"})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
}
> db.t2.dropIndex({name:1,date:1},{name : "联合索引"})
{ "nIndexesWas" : 2, "ok" : 1 }
> 

3.1.4 重建索引

-- 重建集合上所有索引
db.t2.reIndex();

3.2 索引选择三步法

(1)相等测试:按任意顺序把所有相等测试的字段添加到复合索引中。
(2)排序字段:(只有存在多个排序字段,升序/降序才重要)在索引中添加排序字段,其顺序和方向与查询的排序相同。
(3)范围过滤器:首先,为基数最低的字段添加范围过滤器(集合中不同的值最少),接着添加基数次低的范围过滤器,直到基数最高的范围过滤器为止。

如果相等测试或范围过滤器字段没有选择性,就可以省略它们,以减少索引的大小。经验法则是,如果字段没有过滤掉集合中至少90%的文档,就最好在索引中省略它。如果集合上有几个索引,就可能需要提示MongoDB使用正确的索引。

3.3 指定索引选项

3.3.1 后台创建索引

db.t2.createIndex({name:1}, {background:true})

# 终止索引进程
db.currentOp();
db.killOp(<opid>);

测试记录:

> db.t2.createIndex({name:1}, {background:true})

{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 2,
        "numIndexesAfter" : 3,
        "ok" : 1
}
> 

3.3.2 创建唯一索引

> db.t2.createIndex({id:1}, {unique:true})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 3,
        "numIndexesAfter" : 4,
        "ok" : 1
}

3.3.3 创建稀疏索引

> db.t2.createIndex({name:1}, {sparse:true})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
}
> 

3.3.4 创建部分(条件)索引

> db.t2.createIndex({id:1}, {partialFilterExpression:{ cost: { $gt: 10 } } })
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 2,
        "numIndexesAfter" : 3,
        "ok" : 1
}
> 

3.4 使用hint()

hint测试

# 创建索引
db.t2.createIndex({"id":1, "name":1});
# 加hint使用索引
db.t2.find({id: 1, name: 'aaa'}).hint({"id":1, "name":1});
# 不使用任何索引
db.t2.find({id: 1, name: 'aaa'}).hint({$natural:1})

测试记录:

> db.t2.createIndex({"id":1, "name":1});
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 3,
        "numIndexesAfter" : 4,
        "ok" : 1
}
> 
> 
-- 强制不走索引的,明显慢一些
> db.t2.find({id: 1, name: 'aaa'}).hint({$natural:1})
{ "_id" : ObjectId("5facab82677cc70f7ab9358e"), "id" : 1, "name" : "aaa", "date" : ISODate("2020-11-12T03:26:58.366Z") }
> 

参考:

1.https://docs.mongodb.com/v4.2/indexes/#default-id-index
2.https://blog.csdn.net/wzy0623/article/details/83060759

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值