深入理解MongoDB的复合索引

  • A+
所属分类:MongoDB

为什么必要索引?

当你埋怨MongoDB聚拢查询效力低的时刻,可能你就必要斟酌使用索引了,为了便利后续先容,先科普下MongoDB里的索引机制(同样实用于其他的数据库好比mysql)。

当你往某各个聚拢插入多个文档后,每个文档在颠末底层的存储引擎持久化后,会有一个地位信息,经由过程这个地位信息,就能从存储引擎里读出该文档。好比mmapv1引擎里,地位信息是『文件id + 文件内offset 』, 在wiredtiger存储引擎(一个KV存储引擎)里,地位信息是wiredtiger在存储文档时天生的一个key,经由过程这个key能拜访到对应的文档;为便利先容,同一用pos(position的缩写)来代表地位信息。

什么是复合索引

复合索引,即Compound Index,指的是将多个键组合到一路创立索引,如许可以加快匹配多个键的查询。不妨经由过程一个简单的示例懂得复合索引

students聚拢如下:

在name和age两个键分离创立了索引(_id自带索引):

当进行多键查询时,可以经由过程explian()阐发执行环境(成果仅保存winningPlan):

由winningPlan可知,这个查询依次分为IXSCAN和FETCH两个阶段。IXSCAN即索引扫描,使用的是age索引;FETCH即依据索引去查询文档,查询的时刻必要使用name进行过滤。

为name和age创立复合索引:

有了复合索引之后,统一个查询的执行方式就分歧了:

由winningPlan可知,这个查询的次序没有变化,依次分为IXSCAN和FETCH两个阶段。然则,IXSCAN使用的是name与age的复合索引;FETCH即依据索引去查询文档,不必要过滤。

这个示例的数据量太小,并不克不及看出什么问题。然则现实上,当数据量很年夜,IXSCAN返回的索引比拟多时,FETCH时进行过滤将异常耗时。接下来将先容一个真实的案例。

定位MongoDB机能问题

跟着接管的差错数据赓续增长,我们Fundebug已经累计处置3.5亿差错变乱,这给我们的服务赓续带来机能方面的挑战,尤其对付MongoDB集群来说。

对付临盆数据库,设置装备摆设profile,可以记载MongoDB的机能数据。执行以下敕令,则所有跨越1s的数据库读写操作都邑被记载下来。

查询profile所记载的数据,会发现events聚拢的某个查询异常慢:

events聚拢中稀有亿个文档,是以count操作比拟慢也不算太不测。依据profile数据,这个查询耗时28.5s,光阴长得有点离谱。另外,numYield高达1414,这应该便是操作如斯之慢的直接缘故原由。依据MongoDB文档,numYield的寄义是如许的:

The number of times the operation yielded to allow other operations to complete. Typically, operations yield when they need access to data that MongoDB has not yet fully read into memory. This allows other operations that have data in memory to complete while MongoDB reads in data for the yielding operation.

这就意味着年夜量光阴耗费在读取硬盘上,且读了异常多次。可以推想,应该是索引的问题导致的。

不妨使用explian()来阐发一下这个查询(仅保存executionStats):

可知,events聚拢并没有为projectId与createAt树立复合索引,是以IXSCAN阶段采纳的是projectId索引,其nReturned为28338; FETCH阶段必要依据createAt进行过滤,其nReturned为20853,过滤失落了7485个文档;另外,IXSCAN与FETCH阶段的executionTimeMillisEstimate分离为30ms和27815ms,是以根本上所有光阴都耗费在了FETCH阶段,这应该是读取硬盘导致的。

创立复合索引

没有为projectId和createAt创立复合索引是个为难的差错,赶紧解救一下:

在临盆情况构建索引这种事最好是晚上做,这个敕令一共花了年夜概7个小时吧!background设为true,指的是不要壅闭数据库的其他操作,保证数据库的可用性。然则,这个敕令会一直占用着终端,这时不克不及使用CTRL + C,不然会终止索引构建进程。

复合索引创立结果之后,前文的查询就快了许多(仅保存executionStats):

可知,count操作使用了projectId和createAt的复合索引,是以异常快,只花了46ms,机能晋升了快要600倍!!!对照使用复合索引前后的成果,发现totalDocsExamined从28338降到了0,表现使用复合索引之后不再必要去查询文档,只必要扫描索引就好了,如许就不必要去拜访磁盘了,天然快了许多。

参考

MongoDB 复合索引
MongoDB文档:Compound Indexes

总结

以上便是这篇文章的全体内容了,愿望本文的内容对年夜家的进修或者事情具有必定的参考进修代价,假如有疑问年夜家可以留言交流,谢谢年夜家对剧本之家的支撑。

您可能感兴致的文章:

MongoDB索引使用详解MongoDB的根基查询和索引操作办法总结MongoDB机能篇之创立索引,组合索引,独一索引,删除索引和explain执行方案MongoDB中创立索引必要注意的事变pymongo给mongodb创立索引的简单实现办法MongoDB查询字段没有创立索领导致的衔接超时非常解案例分享MongoDB进修条记(六) MongoDB索引用法和效力阐发mongodb处置中文索引与查找字符串详解pymongo为mongodb数据库添加索引的办法MongoDB数据库中索引(index)详解

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: