mongo 索引解析

栏目: 数据库 · 发布时间: 5年前

内容简介:mongo 的索引非常强大,和关系型数据库索引没什么区别。这里主要介绍mongo索引基本知识和mongo本人在索引上的犯的错。db.book.find({"address.0":"addr1"})#shard key index#

mongo 的索引非常强大,和关系型数据库索引没什么区别。这里主要介绍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,但是是值得的。这也是为什么在开始的时候时候说联合index的字段排序顺序是精确匹配字段(=xxx),排序字段(避免在内存中排序,使用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索引 docs.mongodb.com/manual/core…

  • 多键索引是没法查一个数组全部匹配的,会先查第一个元素,后面的会使用filter

  • $elemMatch

    son:{ $elemMatch:{$gt:9,$lt:11}} 这个查询和 son:{$gt:9,$lt:11 }的区别, 后者是只要数组中任意一个字段满足其他一个条件即可,比如第一个字段满足gt:9,第二个字段满足lt:11那么也认为是满足条件。所以使用索引时,只能使用到一个边界条件。

  • 在联合索引中只允许有一个array字段。但是因为mongo是free schema的。可以是不同的字段,只要一个document中只有一个array就行了,在不同的document中可以是不同字段

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

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

注意

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

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

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

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

  3. mongo 中有一个名字叫scalar(标量字段)就是非array,非embedded document这样的字段。针对这些字段的索引与关系型数据库并无差别,无需特殊处理 觉得这篇分享就有点过于强调阅读mongo源码来解决的问题的重要性,因为这个就可以通过上述分析找到root cause yq.aliyun.com/articles/74… #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上独立创建的。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

颠覆式成长

颠覆式成长

惠特尼•约翰逊 / 张瀚文 / 中信出版集团 / 2018-8 / 49.00

你可能想要标新立异、挑战自我,甚至抛弃安逸的事业; 你可能会从目前的行业或公司中跳槽,进入一个完全陌生的崭新领域, 这本书会让你认识到颠覆式成长的意义所在。 成功没有捷径,颠覆也会令人心生惧意,但是在职业发展与个人成长上的回报,会让你克服这种恐惧,让你不断尝试、不断精进。 S型曲线精进模型将帮助你预测自己创新的成长周期,洞悉颠覆自我过程中的心路历程,在变革与颠覆中从容应对,......一起来看看 《颠覆式成长》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具