Mongo Index 摘要 索引种类 array index shard key index mongo index VS cassandra secondary index 参考

Mongo Index
摘要
索引种类
array index
shard key index
mongo index VS cassandra secondary index
参考

mongo 的索引非常强大,和关系型数据库索引没什么区别。这里主要介绍本人在mongo索引上的犯的错。

索引种类

1.单字段索引
2.复合索引
复合索引各个字段的顺序应该是精确匹配字段(=xxx),排序字段(避免在内存中排序,使用index排序),范围查询字段

如db.book.find({company: ‘xxx’, age:{$lt:30}).sort({name:1})
db.book.find().explain("executionStats")可以很好的列出查询执行计划。
总共有四个重要参数:
executionTimeMills:查询执行的时间
nReturned: 返回的文档数
totalKeysExamined: 索引扫描数
totalDocsExamined: 文档扫描数

当然希望nReturned数目=totalKeysExamined
不扫描文档。(后面不挂着数据,index及数据)

或者nReturned = totalKeysExamined = totalDocsExamined
如果有排序,为了不让排序在内存中进入,在nReturned = totalDocsExamined的基础上,totalKeysExamined可以大于nReturned。对于大数据量的内存排序会非常消耗性能

如果我们创建一个复合索引是db.book.ensureIndex({company:1,age:1,name:1})
这时候nReturned = totalKeysExamined = totalDocsExamined
。因为查询会用到index,不需要额外的文档扫描。但是会有SORT stage。即在内存中排序。

尝试加一个index,在排序字段放在扫描字段前面
db.book.ensureIndex({company:1,name:1,age:1})
这时候发现mongo选择了新的index

 "indexBounds" : {
         "company" : [
                 "["a", "a"]"
         ],
         "name" : [
                 "[MinKey, MaxKey]"
         ],
         "age" : [
                 "[-1.#INF, 30.0)"
         ]
 },

且执行计划中有reject SORT排序

"rejectedPlans" : [
        {
                "stage" : "SORT",
                "sortPattern" : {
                        "name" : 1
                },

这时候nReturned = totalDocsExamined < totalKeysExamined 多扫描了index。但是是值得的。
如{name:1,address:1},包含的是两个查询

db.book.find({name:"xxx"})
db.book.find({name:"xxx",address:"xxx"})

但是如果你的查询不是范围查询。而是精确匹配字段。那还是使用原来的index。因为这时候排序字段用到了index查询,不需要SORT阶段了

db.book.find({company:'a',age:30}).sort({name:1}).explain("executionStats")
 "indexBounds" : {
         "company" : [
                 "["a", "a"]"
         ],
         "age" : [
                 "[30.0, 30.0]"
         ],
         "name" : [
                 "[MinKey, MaxKey]"
         ]
 },

3.多键索引
如array索引

4.唯一索引
db.book.createIndex({“name”:1},{“unique”:true})
mongo 默认创建的不是唯一索引,需要显示指定。唯一索引会对数据进行校验,不允许重复数据。

  1. sharding cluster 索引
    索引是在各个shard上面单独建立的,不是全局的。
    sharding cluster 环境,只允许_id,和shard key建立unique index.因为unique index 需要shard 之间通信,违背了shard 设计理念。所以需要避免

注意
1. 当一个collection上面有多个index
某个查询可能命中多个index,这时候mongo是如何选择索引的呢。

首先mongo会对某类类似查询语句在可能命中的index都执行一遍,并行执行的,最早返回100个结果找出最优的index,然后记住这类查询所用到的索引。以后查询操作就使用这个索引。当有index更改时,再去更改这个值。

  1. 当有一个复合索引
    {name:1,address:1,email:1}

这时候有一个新的查询{name:xxx,address:xxx,phone:xxx}
可以用到已经创建的复合索引。这时候你会不会单独在创建一个索引呢。
优势是这个查询也很快,缺点是多了一个index,减弱了插入性能。

这个可能需要衡量前两个字段过滤掉了多少数据,phone这个字段占剩下数据量的多少来决定需要创建什么样的index.

array index

mongo 可以对array建立index,注意是将index中的每个元素都作为index key,进行索引。所以对array建立index一定要十分小心,很容易导致index size 很大。另外mongo支持指定array某一列进行查询。

test.book
{
    _id:1,
    name:english,
    address:[addr1,addr2]
}

db.book.find({“address.0”:”addr1”})
当对address创建index,这样的查询是用不到index的。只有基于array的查询,index才能有效。
mongo并没有那么神奇的在创建index的同时还保留列数。

shard key index

  • 表中有数据
    表中有数据再创建shard key,需要首先创建对应的index,才能去创建shard key
  • 表中无数据
    表中无数据,创建shard key的同时,mongo会自动创建一个对应字段的index
sh.shardCollection("test.book",{name:1,address:1})

会自动创建index

{name:1,address:1}

mongo index VS cassandra secondary index

1.query 过程
cassandra query,首先根据partitioner key去找对应partition,partition中的数据是按照clustering key排序的。注意是按照clustering key排序的,clustering key这个字段 不是index。

mongo(sharding cluster) query,首先根据给定的shard key去找在哪个节点上,然后将请求发送到此节点。进行查找。
如果你的query case是

db.book.find({name:"xxx",address:"xxx"})

而shard key是name。此外再单独为address建立一个index。这时候你的query其实是命中的address 的单字段index。而不是预想的已经将name数据过滤了。这点和cassandra有很大的不同

2.范围
cassandra secondary index 是local的,在每个节点上。
mongo 的index是全局的。
mongo sharding cluster 环境,index也是在各个shard上独立创建的。

参考

http://www.mongoing.com/eshu_explain3