MongoDB索引Index(二)

1、索引管理

(1)创建索引并在后台运行

db.集合名.createIndex({"字段":排序方式}, {background: true});

(2)获取针对某个集合的索引

db.集合名.getIndexes()

(3)索引的大小

db.集合名.totalIndexSize()

(4)索引的重建

db.集合名.reIndex()

(5)索引的删除

db.集合名.dropIndex("INDEX-NAME")  // 删除指定索引
db.集合名.dropIndexes()  // 删除集合全部索引
注意: _id 对应的索引是删除不了的

2、explain 分析

        使用js循环 插入100万条数据 不使用索引字段 查询查看执行计划 ,然后给某个字段建立索引,使用索引字段作为查询条件 再查看执行计划进行分析

/** 向lg_resume 中插入100 万条数据 */
for(var i=0;i<1000000;i++){
    db.lg_resume.insert({id:i,name:"test"+i,salary:(Math.random()*20000).toFixed(2)});
}

explain()也接收不同的参数,通过设置不同参数我们可以查看更详细的查询计划。

  • queryPlanner:queryPlanner是默认参数,具体执行计划信息参考下面的表格。
  • executionStats:executionStats会返回执行计划的一些统计信息(有些版本中和allPlansExecution等同)。
  • allPlansExecution:allPlansExecution用来获取所有执行计划,结果参数基本与上文相同。

queryPlanner 默认参数

参数含义
plannerVersion查询计划版本
namespace要查询的集合(该值返回的是该query所查询的表)数据库.集合
indexFilterSet针对该query是否有indexFilter
parsedQuery查询条件
winningPlan被选中的执行计划
winningPlan.stage被选中执行计划的stage(查询方式),常见的有:COLLSCAN/全表扫描:(应该知道就是CollectionScan,就是所谓的“集合扫描”,和mysql中table scan/heap scan类似,这个就是所谓的性能最烂最无奈的由来)、IXSCAN/索引扫描:(是IndexScan,这就说明我们已经命中索引了)、FETCH/根据索引去检索文档SHARD_MERGE/合并分片结果IDHACK/针对_id进行查询等
winningPlan.inputStage用来描述子stage,并且为其父stage提供文档和索引关键字。
winningPlan.stage的child stage如果此处是IXSCAN,表示进行的是index scanning。
winningPlan.keyPattern所扫描的index内容
winningPlan.indexNamewinning plan所选用的index。
winningPlan.isMultiKey是否是Multikey,此处返回是false,如果索引建立在array上,此处将是true。
winningPlan.direction此query的查询顺序,此处是forward,如果用了.sort({字段:-1})将显示backward。
filter过滤条件
winningPlan.indexBoundswinningplan所扫描的索引范围,如果没有制定范围就是[MaxKey,MinKey],这主要是直接定位到mongodb的chunck中去查找数据,加快数据读取。
rejectedPlans被拒绝的执行计划的详细返回,其中具体信息与winningPlan的返回中意义相同,故不在此赘述)
serverInfoMongoDB服务器信息

executionStats参数

参数含义
executionSuccess是否执行成功
nReturned返回的文档数
executionTimeMillis执行耗时
totalKeysExamined索引扫描次数
totalDocsExamined文档扫描次数
executionStages这个分类下描述执行的状态
stage扫描方式,具体可选值与上文的相同
nReturned查询结果数量
executionTimeMillisEstimate检索document获得数据的时间
inputStage.executionTimeMillisEstimate该查询扫描文档 index所用时间
works工作单元数,一个查询会分解成小的工作单元
advanced优先返回的结果数
docsExamined文档检查数目,与totalDocsExamined一致。检查了总共的document个数,而从返回上面的nReturned数量

executionStats返回逐层分析

  第一层,executionTimeMillis最为直观explain返回值是executionTimeMillis值,指的是这条语句的执行时间,这个值当然是希望越少越好。

   其中有3个executionTimeMillis,分别是:

  • executionStats.executionTimeMillis 该query的整体查询时间。
  • executionStats.executionStages.executionTimeMillisEstimate 该查询检索document获得数据的时间。
  • executionStats.executionStages.inputStage.executionTimeMillisEstimate 该查询扫描文档 index所用时间。

  第二层,index与document扫描数与查询返回条目数 这个主要讨论3个返回项 nReturnedtotalKeysExamined、totalDocsExamined,分别代表该条查询返回的条目、索引扫描条目、文档扫描条目。 这些都是直观地影响到executionTimeMillis,我们需要扫描的越少速度越快。 对于一个查询,我们最理想的状态是:nReturned=totalKeysExamined=totalDocsExamined

  第三层,stage状态分析 那么又是什么影响到了totalKeysExamined和totalDocsExamined?是stage的类型。

    类型列举如下:

  • COLLSCAN:全表扫描
  • IXSCAN:索引扫描
  • FETCH:根据索引去检索指定document
  • SHARD_MERGE:将各个分片返回数据进行merge
  • SORT:表明在内存中进行了排序
  • LIMIT:使用limit限制返回数
  • SKIP:使用skip进行跳过
  • IDHACK:针对_id进行查询
  • SHARDING_FILTER:通过mongos对分片数据进行查询
  • COUNT:利用db.coll.explain().count()之类进行count运算
  • TEXT:使用全文索引进行查询时候的stage返回
  • PROJECTION:限定返回字段时候stage的返回

对于普通查询,我希望看到stage的组合(查询的时候尽可能用上索引):

  • Fetch+IDHACK
  • Fetch+IXSCAN
  • Limit+(Fetch+IXSCAN)
  • PROJECTION+IXSCAN
  • SHARDING_FITER+IXSCAN

不希望看到包含如下的stage:

  • COLLSCAN(全表扫描)
  • SORT(使用sort但是无index)
  • COUNT 不使用index进行count)

allPlansExecution参数

queryPlanner 参数和executionStats的拼接

3、慢查询分析

  • 开启内置的查询分析器,记录读写操作效率
    • db.setProfilingLevel(n,m),n的取值可选0,1,2
      • 0表示不记录
      • 1表示记录慢速操作,如果值为1,m必须赋值单位为ms,用于定义慢速查询时间的阈值
      • 2表示记录所有的读写操作
  • 查询监控结果
    • db.system.profile.find().sort({millis:-1}).limit(3)
  • 分析慢速查询
    • 应用程序设计不合理、不正确的数据模型、硬件配置问题,缺少索引等
  • 解读explain结果 确定是否缺少索引

4、MongoDB 索引底层实现原理分析

        MongoDB 是文档型的数据库,它使用BSON 格式保存数据,比关系型数据库存储更方便。比如之前关系型数据库中处理用户、订单等数据要建立对应的表,还要建立它们之间的关联关系。但是BSON就不一样了,我们可以把一条数据和这条数据对应的数据都存入一个BSON对象中,这种形式更简单,通俗易懂。MySql是关系型数据库,数据的关联性是非常强的,区间访问是常见的一种情况,底层索引组织数据使用B+树,B+树由于数据全部存储在叶子节点,并且通过指针串在一起,这样就很容易的进行区间遍历甚至全部遍历。MongoDB使用B-树,所有节点都有Data域,只要找到指定索引就可以进行访问,单次查询从结构上来看要快于MySql。

B-树是一种自平衡的搜索树,形式很简单:

B-树的特点:

  • 多路 非二叉树
  • 每个节点 既保存数据 又保存索引
  • 搜索时 相当于二分查找 

B+树是B-树的变种

 B+ 树的特点:

  • 多路非二叉
  • 只有叶子节点保存数据
  • 搜索时 也相当于二分查找
  • 增加了 相邻节点指针

        从上面我们可以看出最核心的区别主要有俩,一个是数据的保存位置,一个是相邻节点的指向。就是这俩造成了MongoDB和MySql的差别。

  1. B+树相邻接点的指针可以大大增加区间访问性,可使用在范围查询等,而B-树每个节点 key 和data 在一起 适合随机读写 ,而区间查找效率很差。
  2. B+树更适合外部存储,也就是磁盘存储,使用B-结构的话,每次磁盘预读中的很多数据是用不上的数据。因此,它没能利用好磁盘预读的提供的数据。由于节点内无 data 域,每个节点能索引的范围更大更精确。
  3. 注意这个区别相当重要,是基于(1)(2)的,B-树每个节点即保存数据又保存索引 树的深度小,所以磁盘IO的次数很少,B+树只有叶子节点保存,较B树而言深度大磁盘IO多,但是区间访问比较好。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

悠然予夏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值