Mongodb索引和执行计划 hint 慢查询
查询索引
- 索引存放在system.indexes集合中
- > show tables
- address
- data
- person
- system.indexes
- 默认会为所有的ID建上索引 而且无法删除
- > db.system.indexes.find()
- { "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "mydb.person" }
- { "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "mydb.address" }
- { "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "mydb.data" }
- 单独查询一个集合的索引
- > db.person.getIndexes();
- [
- {
- "v" : 1,
- "key" : {
- "_id" : 1
- },
- "name" : "_id_",
- "ns" : "mydb.person"
- }
- ]
- >
创建索引
- > db.person.find();
- { "_id" : ObjectId("593011c8a92497992cdfac10"), "name" : "xhj", "age" : 30, "address" : DBRef("address", ObjectId("59314b07e693aae7a5eb72ab")) }
- { "_id" : ObjectId("59301270a92497992cdfac11"), "name" : "zzj", "age" : 2 }
- { "_id" : ObjectId("593015fda92497992cdfac12"), "name" : "my second child", "age" : "i do not know" }
- { "_id" : ObjectId("592ffd872108e8e79ea902b0"), "name" : "zjf", "age" : 30, "address" : { "province" : "河南省", "city" : "南阳市", "building" : "桐柏县" } }
- 1升序 -1降序
- > db.person.ensureIndex({age:1});
- {
- "createdCollectionAutomatically" : false,
- "numIndexesBefore" : 1,
- "numIndexesAfter" : 2,
- "ok" : 1
- }
- 可以在集合上创建索引
- > db.person.ensureIndex({address:1});
- {
- "createdCollectionAutomatically" : false,
- "numIndexesBefore" : 2,
- "numIndexesAfter" : 3,
- "ok" : 1
- }
- 复合索引
- > db.person.ensureIndex({name:1,address:1});
- {
- "createdCollectionAutomatically" : false,
- "numIndexesBefore" : 3,
- "numIndexesAfter" : 4,
- "ok" : 1
- }
- 唯一索引:
- > db.person.ensureIndex({name:1},{unique:true});
- {
- "createdCollectionAutomatically" : false,
- "numIndexesBefore" : 4,
- "numIndexesAfter" : 5,
- "ok" : 1
- }
复合索引使用前缀匹配,所以创建复合索引的时候,要把经常会有的部分查询作为前缀。
删除索引:
- 删除一个索引
- > db.person.dropIndex({name:1});
- { "nIndexesWas" : 5, "ok" : 1 }
- 删除所有索引
- > db.person.dropIndexes();
- {
- "nIndexesWas" : 4,
- "msg" : "non-_id indexes dropped for collection",
- "ok" : 1
- }
查看执行计划的方法:explain ()
winningPlan是最终的执行计划 其中的indexBounds索引计划
- 在age上建立索引
- > db.person.ensureIndex({age:1});
- {
- "createdCollectionAutomatically" : false,
- "numIndexesBefore" : 1,
- "numIndexesAfter" : 2,
- "ok" : 1
- }
- > db.person.getIndexes();
- [
- {
- "v" : 1,
- "key" : {
- "_id" : 1
- },
- "name" : "_id_",
- "ns" : "mydb.person"
- },
- {
- "v" : 1,
- "key" : {
- "age" : 1
- },
- "name" : "age_1",
- "ns" : "mydb.person"
- }
- ]
- 查看执行计划 indexBounds可以看到走了age的索引
- > db.person.find({age:30}).explain();
- {
- "queryPlanner" : {
- "plannerVersion" : 1,
- "namespace" : "mydb.person",
- "indexFilterSet" : false,
- "parsedQuery" : {
- "age" : {
- "$eq" : 30
- }
- },
- "winningPlan" : {
- "stage" : "FETCH",
- "inputStage" : {
- "stage" : "IXSCAN",
- "keyPattern" : {
- "age" : 1
- },
- "indexName" : "age_1",
- "isMultiKey" : false,
- "direction" : "forward",
- "indexBounds" : {
- "age" : [
- "[30.0, 30.0]"
- ]
- }
- }
- },
- "rejectedPlans" : [ ]
- },
- "serverInfo" : {
- "host" : "localhost.localdomain",
- "port" : 27017,
- "version" : "3.0.6",
- "gitVersion" : "1ef45a23a4c5e3480ac919b28afcba3c615488f2"
- },
- "ok" : 1
- }
- 没有走索引的计划是这样的
- > db.person.find({name:'zjf'}).explain();
- {
- "queryPlanner" : {
- "plannerVersion" : 1,
- "namespace" : "mydb.person",
- "indexFilterSet" : false,
- "parsedQuery" : {
- "name" : {
- "$eq" : "zjf"
- }
- },
- "winningPlan" : {
- "stage" : "COLLSCAN",
- "filter" : {
- "name" : {
- "$eq" : "zjf"
- }
- },
- "direction" : "forward"
- },
- "rejectedPlans" : [ ]
- },
- "serverInfo" : {
- "host" : "localhost.localdomain",
- "port" : 27017,
- "version" : "3.0.6",
- "gitVersion" : "1ef45a23a4c5e3480ac919b28afcba3c615488f2"
- },
- "ok" : 1
- }
强制索引 hint()方法:
- > db.person.ensureIndex({name:1,age:1});
- {
- "createdCollectionAutomatically" : false,
- "numIndexesBefore" : 3,
- "numIndexesAfter" : 4,
- "ok" : 1
- }
- > db.person.getIndexes();
- [
- {
- "v" : 1,
- "key" : {
- "_id" : 1
- },
- "name" : "_id_",
- "ns" : "mydb.person"
- },
- {
- "v" : 1,
- "key" : {
- "age" : 1
- },
- "name" : "age_1",
- "ns" : "mydb.person"
- },
- {
- "v" : 1,
- "key" : {
- "name" : 1
- },
- "name" : "name_1",
- "ns" : "mydb.person"
- },
- {
- "v" : 1,
- "key" : {
- "name" : 1,
- "age" : 1
- },
- "name" : "name_1_age_1",
- "ns" : "mydb.person"
- }
- ]
- //如果不加hint 默认走age上的索引。
- > db.person.find({age:{$gt:0}}).explain();
- {
- "queryPlanner" : {
- "plannerVersion" : 1,
- "namespace" : "mydb.person",
- "indexFilterSet" : false,
- "parsedQuery" : {
- "age" : {
- "$gt" : 0
- }
- },
- "winningPlan" : {
- "stage" : "FETCH",
- "inputStage" : {
- "stage" : "IXSCAN",
- "keyPattern" : {
- "age" : 1
- },
- "indexName" : "age_1",
- "isMultiKey" : false,
- "direction" : "forward",
- "indexBounds" : {
- "age" : [
- "(0.0, inf.0]"
- ]
- }
- }
- },
- "rejectedPlans" : [ ]
- },
- "serverInfo" : {
- "host" : "localhost.localdomain",
- "port" : 27017,
- "version" : "3.0.6",
- "gitVersion" : "1ef45a23a4c5e3480ac919b28afcba3c615488f2"
- },
- "ok" : 1
- }
- //使用hint
- > db.person.find({age:{$gt:0}}).hint({name:1,age:1}).explain();
- {
- "queryPlanner" : {
- "plannerVersion" : 1,
- "namespace" : "mydb.person",
- "indexFilterSet" : false,
- "parsedQuery" : {
- "age" : {
- "$gt" : 0
- }
- },
- "winningPlan" : {
- "stage" : "KEEP_MUTATIONS",
- "inputStage" : {
- "stage" : "FETCH",
- "filter" : {
- "age" : {
- "$gt" : 0
- }
- },
- "inputStage" : {
- "stage" : "IXSCAN",
- "keyPattern" : {
- "name" : 1,
- "age" : 1
- },
- "indexName" : "name_1_age_1",
- "isMultiKey" : false,
- "direction" : "forward",
- "indexBounds" : {
- "name" : [
- "[MinKey, MaxKey]"
- ],
- "age" : [
- "[MinKey, MaxKey]"
- ]
- }
- }
- }
- },
- "rejectedPlans" : [ ]
- },
- "serverInfo" : {
- "host" : "localhost.localdomain",
- "port" : 27017,
- "version" : "3.0.6",
- "gitVersion" : "1ef45a23a4c5e3480ac919b28afcba3c615488f2"
- },
- "ok" : 1
- }
查看执行情况:
- db.person.find({name:'zjf'}).explain('executionStats');
- {
- "queryPlanner" : {
- "plannerVersion" : 1,
- "namespace" : "mydb.person",
- "indexFilterSet" : false,
- "parsedQuery" : {
- "name" : {
- "$eq" : "zjf"
- }
- },
- "winningPlan" : {
- "stage" : "FETCH",
- "inputStage" : {
- "stage" : "IXSCAN",
- "keyPattern" : {
- "name" : 1
- },
- "indexName" : "name_1",
- "isMultiKey" : false,
- "direction" : "forward",
- "indexBounds" : {
- "name" : [
- "[\"zjf\", \"zjf\"]"
- ]
- }
- }
- },
- "rejectedPlans" : [
- {
- "stage" : "FETCH",
- "inputStage" : {
- "stage" : "IXSCAN",
- "keyPattern" : {
- "name" : 1,
- "age" : 1
- },
- "indexName" : "name_1_age_1",
- "isMultiKey" : false,
- "direction" : "forward",
- "indexBounds" : {
- "name" : [
- "[\"zjf\", \"zjf\"]"
- ],
- "age" : [
- "[MinKey, MaxKey]"
- ]
- }
- }
- }
- ]
- },
- "executionStats" : {
- "executionSuccess" : true,
- "nReturned" : 1,
- "executionTimeMillis" : 0,
- "totalKeysExamined" : 1,
- "totalDocsExamined" : 1,
- "executionStages" : {
- "stage" : "FETCH",
- "nReturned" : 1,
- "executionTimeMillisEstimate" : 0,
- "works" : 3,
- "advanced" : 1,
- "needTime" : 0,
- "needFetch" : 0,
- "saveState" : 0,
- "restoreState" : 0,
- "isEOF" : 1,
- "invalidates" : 0,
- "docsExamined" : 1,
- "alreadyHasObj" : 0,
- "inputStage" : {
- "stage" : "IXSCAN",
- "nReturned" : 1,
- "executionTimeMillisEstimate" : 0,
- "works" : 2,
- "advanced" : 1,
- "needTime" : 0,
- "needFetch" : 0,
- "saveState" : 0,
- "restoreState" : 0,
- "isEOF" : 1,
- "invalidates" : 0,
- "keyPattern" : {
- "name" : 1
- },
- "indexName" : "name_1",
- "isMultiKey" : false,
- "direction" : "forward",
- "indexBounds" : {
- "name" : [
- "[\"zjf\", \"zjf\"]"
- ]
- },
- "keysExamined" : 1,
- "dupsTested" : 0,
- "dupsDropped" : 0,
- "seenInvalidated" : 0,
- "matchTested" : 0
- }
- }
- },
- "serverInfo" : {
- "host" : "localhost.localdomain",
- "port" : 27017,
- "version" : "3.0.6",
- "gitVersion" : "1ef45a23a4c5e3480ac919b28afcba3c615488f2"
- },
- "ok" : 1
- }
Mongodb的索引使用的是B-树。
hash索引:
散列索引使用索引字段的值的散列值来维护条目。
散列索引的重要特征是hash后的键值是均匀分布的,索引最适合的是做分片键。
db.collection.createIndex( { _id: "hashed" } )
MongoDB支持任何单个字段的散列索引。 散列函数折叠嵌入文档并计算整个值的散列值,但不支持多键(即数组)索引。
您不得创建具有散列索引字段或在散列索引上指定唯一约束的复合索引; 但是,您可以在同一字段上创建散列索引和升序/降序(即非散列)索引:MongoDB将使用范围查询的标量索引。
警告
MongoDB散列索引在浮动之前将浮点数截断为64位整数。 例如,散列索引将为保持值为2.3,2.2和2.9的字段存储相同的值。 为了防止冲突,不要使用不能可靠地转换为64位整数(然后返回到浮点)的浮点数的散列索引。 MongoDB散列索引不支持大于253的浮点值。
散列索引支持等值查询。
索引大小
为了达到更快的处理效果,请确保您的索引能完整地和内存相适应,这样可以避免从磁盘上读取索引。
可以使用帮助函数 db.collection.totalIndexSize() 来检查索引的大小,返回的数值单位是字节:
> db.collection.totalIndexSize()
4294976499
上述例子展示了一个几乎4.3GB的索引。为了确保索引与内存相适应,您不仅需要有那么多足够可用的内存用于索引,还要有足够的内存用于剩下的 working set 。
稀疏索引
稀疏索引(或者称间隙索引)就是只包含有索引字段的文档的条目,跳过索引键不存在的文档
创建间隙索引示例:
db.addresses.createIndex( { "xmpp_id": 1 }, { sparse: true } )
这个示例,哪些不包含xmpp_id的键(列)的文档将不会被索引
间隙索引不会被使用到的情形
如果一个间隙索引会导致查询或者排序操作得到一个不完整结果集的时候,MongoDB将不会使用这个索引,hint提示除外
如果集合中有大量的数据都不包含该键值,那么应该使用稀疏索引。
覆盖索引:
整个结果集都是从索引中获取。
慢查询分析:
慢查询分析流程:
1.用慢查询日志(system.profile)找到超过200ms的语句
2.然后再通过.explain()解析影响行数,分析为什么超过200ms
3.决定是不是需要添加索引
开启慢查询:
db.setProfilingLevel(1,200)
参数:
- 0:关闭,不收集任何数据。
- 1:收集慢查询数据,默认是100毫秒。
- 2:收集所有数据
查看结果:
db.system.profile.find()
注意:索引基本上可以说是常驻在内存中的,索引如果数据量达到亿级,索引的 数量越少越好,因为会占据大量的内存。网上的说法,100万条索引约占50M内存。如果一个亿,那么将占据5g内存。
以下来自网络:
不要被FindOne({_id:xxx}).Items[3].ItemType这优雅的代码欺骗,这是非常慢的,他几乎谋杀你所有的流量。
无论后面是什么 FindOne({_id:xxx})总是返回给你完整的Value,我们的100条道具,少说也有6~8K.
这样的查询流量已经很大了,如果你采用MongoDB方案一设计,你的单个Value是包含一个用户的所有数据的,他会更大。
如果查询客户端和数据库服务器不在同一个机房,流量将成为一个很大的瓶颈。
我们应该使用的查询函数是FindOne({_id:xxx},filter),filter里面就是设置返回的过滤条件,这会在发送给你以前就过滤掉
比如FindOne({_id:xxx},{Items:{"$slice":[3,1]}}),这和上面那条优雅的代码是完成同样功能,但是他消耗很少的流量
这和问题二相对的,不要暴力的FindOne,也尽量不要暴力的Update一整个节点。虽然MangoDB的性能挺暴力的,IO性能极限约等于MongoDB性能,暴力的Update就会在占用流量的同时迎接IO的性能极限。
除了创建节点时的Insert或者Save之外,所有的Update都应该使用修改器精细修改.
比如Update({_id:xxx},{$set:{"Items.3.Item.Health":38}});//修改第三把武器的健康值
Mongodb索引和执行计划 hint 慢查询的更多相关文章
- python/MySQL(索引、执行计划、BDA、分页)
---恢复内容开始--- python/MySQL(索引.执行计划.BDA.分页) MySQL索引: 所谓索引的就是具有(约束和加速查找的一种方式) 创建索引的缺点是对数据进行(修改.更新.删除) ...
- MySQL for OPS 03:索引和执行计划
写在前面的话 啥是索引?以一本书为例,如果想要找到某一指定章节的某一小节,书薄还好,如果书厚,可能就会找的头皮发麻.于是便出现了目录,让用户更容易查找到自己所需要的东西.索引就类似一张表的目录.其存在 ...
- oracle -- 查询执行计划,判读查询语句优劣
以oracle的scott账户:找到员工表中薪水大于本部门平均薪水的员工为例 多表查询方式: select e.empno, e.ename, e.sal, d.avgsal from emp e, ...
- 第九课——MySQL优化之索引和执行计划
一.创建索引需要关注什么? 1.关注基数列唯一键的数量: 比如性别,该列只有男女之分,所以性别列基数是2: 2.关注选择性列唯一键与行数的比值,这个比值范围在0~1之前,值越小越好: 其实,选择性列唯 ...
- SQL Server索引的执行计划
如何知道索引有问题,最直接的方法就是查看执行计划.通过执行计划,可以回答表上的索引是否被使用的问题. (1)包含索引:避免书签查找 常见的索引方面的性能问题就是书签查找,书签查找分为RID查找和键值查 ...
- mongodb索引--1亿条记录的查询从55.7秒到毫秒级别<补充版>
从头开始,验证mongodb的索引的好处.(window7环境下) 下载mongodb服务器,并解压到d盘,并使用以下命令启动 mongod --dbpath D:\mongodb\data mong ...
- mysql的索引和执行计划
一.mysql的索引 索引是帮助mysql高效获取数据的数据结构.本质:索引是数据结构 1:索引分类 普通索引:一个索引只包含单个列,一个表可以有多个单列索引. 唯一索引:索引列的值必须唯一 ,但允许 ...
- Solr-DIH建立索引并执行简单初步的查询
我们将solr的安装目录设置为$SOLR_INSTALL, ./solr start,不使用任何原有的examples来进行,启动完成后,不存在任何的core,提示No cores availab ...
- 第二百八十八节,MySQL数据库-索引、limit分页、执行计划、慢日志查询
MySQL数据库-索引.limit分页.执行计划.慢日志查询 索引,是数据库中专门用于帮助用户快速查询数据的一种数据结构.类似于字典中的目录,查找字典内容时可以根据目录查找到数据的存放位置,然后直接获 ...
随机推荐
- Python学习之初识
第一章 1.1 typora 的安装与使用 1.1.1 标题的创建: 方法一:用 ###+空格 表示标题,几个#就是几级标题 方法二:菜单栏-->段落-->选择标题 1.1.2 有序列表与 ...
- 分布式锁用Redis还是ZooKeeper?(转载)
文章系网络转载,侵删. 来源:https://zhuanlan.zhihu.com/p/73807097 为什么用分布式锁?在讨论这个问题之前,我们先来看一个业务场景. 图片来自 Pexels 为什么 ...
- sqlalchemy链接数据库
from sqlalchemy import create_engine HOSTNAME = '127.0.0.1' PORT = 3306 DATABASE = 'first_sqlalchemy ...
- linux c++模拟简易网络爬虫
/* * To change this license header, choose License Headers in Project Properties. * To change this t ...
- Spring 最常用的 7 大类注解,史上最强整理!
随着技术的更新迭代,Java5.0开始支持注解.而作为java中的领军框架spring,自从更新了2.5版本之后也开始慢慢舍弃xml配置,更多使用注解来控制spring框架. 而spring的的注解那 ...
- nginx反向代理_负载均衡
注意ip地址为: 虚拟机ip设置 TYPE="Ethernet"BOOTPROTO="static"NAME="enp0s3"DEVICE= ...
- 【计算机网络】-介质访问子层-(信道划分介质访问控制&随机访问介质访问控制)
[计算机网络]-介质访问子层-概述 介质访问控制子层功能 解决信道争用的协议,即用于多路访问信道上确定下一个使用者的协议 是数据链路层协议的一部分 介质访问控制子层位置 位于数据链路层的底部! 信道分 ...
- 在Qt5使用中文(vs环境)
如果是使用mingw版本的Qt create, 也就是使用GCC编译器应该没那么多事吧. 不过我还是用惯了VS呢. 好了,废话不多说,开始总结vs下乱码的解决方案. vs2003 把源码存成 utf- ...
- PYQT5 pyinstaller 打包工程
win+R 输入cmd 回车 首先安装 pyinstaller : pip install pyinstaller 安装 pywin32: pip install pywin32 在cmd中输入工程 ...
- java中super总结
1:super 可以在子类调用父类中的成员变量(包括static修饰的变量)和方法(包括static修饰的方法) 2:super 可以调用父类的构造方法 super(参数列表),在没有定义时,并且没有 ...