Mongodb索引优化

在使用数据库时,索引是必然会遇到的,因为使用它理论上可以优化查询效率,但如果使用不当,虽然也可以提高一定的效率,但抱着精益求精的态度,我们还是应该试试看有没有更好的索引。

Mongodb的索引

Mongodb提供了丰富的索引类型,用的比较多的有单字段索引(Single Field Indexes)、复合索引(Compound Indexes),复合索引中用的最多的就应该是多键索引(Multikey Indexes),其他的比如文本索引(Text Indexes)、2dsphere索引等,我也没有接触过。
从2.6版本开始有一个新特性:索引交叉(Index Intersection),简单来说,它可以根据你的查询条件,同时利用两个索引,这样可以在一定程度上减少你的索引数量,毕竟索引本身也是需要占用存储空间的。但我目前并没有在项目中使用过这种特性,因为我在测试中如果对a、b两个字段单独建立索引,如果查询语句用的是a、b两个字段,用explain时,结果并没有直接显示,因为executionStats中使用的依旧是单独索引,效率就很低了。所以保险起见,我还是用的是多键索引。

Mongodb是如何使用多键索引的

与查询顺序无关

正常情况下,Mongodb会根据你建立的索引和查询条件决定具体使用的索引,比如你的查询字段的顺序是a_b,而你的索引顺序是b_a,此时,Mongodb会进行一次类似重排序的过程,利用索引a_b。博主在第一次接触到Mongodb的时候就因为这点感觉很神奇,因为我之前所接触的mysql、oracle要求查询顺序严格等于索引顺序才可以使用。

不等于符号并不十分影响索引的使用

而且,就算你的查询条件里有 i n 、 in、 inlte这种不等于的情况,依旧可以使用索引,比如你的索引是a_b_c,查询是{a : {KaTeX parse error: Expected 'EOF', got '}' at position 9: in : ...}̲, b : {lte : …}, c : {$gte : …}},最终依旧可以使用a_b_c索引,只是其totalKeysExamined会比nReturned大很多。

如何优化索引

考虑各个索引字段的取值范围

假设你有一个collection名叫dataStatistic(数据统计),里面有字段:id、dateStr、eventType、playerId这4个字段,一般说来,dateStr一天一个,evenType数量固定(假设只有10个),playerId数量很大(假设有10W),如果你查询时最常用的条件是{ dateStr : ..., eventType : ..., playerId : ... },那么,最好将索引建立为{playerId : 1, dateStr : 1, evenType : 1},因为playerId的取值很丰富,拥有相同playerId的文档很少,这样可以筛选出更少的结果,增加查询效率。

考虑每一个查询条件所能筛选的结果

先说一个概念查询优化器

查询优化中最核心的问题就是精确估算不同查询计划的成本。优化器在估算查询计划的成本时,会使用一个数学模型,该模型又依赖于对每个查询计划中涉及的最大数据量的基数性(或者叫重数)的估算。而对基数性的估算又依赖于对查询中谓词选择因数(selection factor of predicates)的估算。过去,数据库系统在估算选择性时,要使用每个字段中值的分布情况的详尽统计信息,比如直方图。这种技术对于估算孤立谓词的选择符效果很好。然而,很多查询的谓词是相互关联的,例如 select count(*) from R where R.make='Honda' and R.model='Accord'。查询谓词经常会高度关联(比如,model='Accord'的前提条件是make='Honda'),而估计这种关联的选择性非常困难。查询优化器之所以会选择低劣的查询计划,一方面是因为对基数性估算不准,另一方面就是因为遗漏了很多关联性。而这也是为什么数据库管理员应该经常更新数据库统计信息(特别是在重要的数据加载和卸载之后)的原因。(译自维基百科:http://en.wikipedia.org/wiki/Query_optimizer。)

Mongodb中也有,叫Query Optimization,但它的解释确实比较少。

一般来说,Mongodb查询或默认让gt/gte/lt/lte放到最后查询,然后匹配索引,如果匹配不到索引,则会再次寻找。你在设计索引时也需要考虑这点。但如果有两个字段都是不等于这样的查询呢,此时你就要考虑这两个条件谁可以筛选更多的结果,谁就在索引中更靠前。有一个比较方便的方法$hint,它可以强制你的查询使用哪个索引,这样我们就可以更加方便地使用索引了。

总结

针对Mongodb的索引,我也是刚开始接触,其中索引的知识也是靠着explain()方法自己测试,加上官方文档的辅助(因为我感觉官方文档很多东西没有讲清楚,比如之前说过的Index Intersection究竟是如何同时利用多个索引的、Query Optimization选择索引的依据),也让我知道了不光只是建立索引就够了,更多还需要根据使用场景进行优化。

有兴趣的话可以看看我的私人博客,说不定会有意外的惊喜。

你可能感兴趣的:(数据库)