美文网首页我爱编程
Mongodb索引探索(一)

Mongodb索引探索(一)

作者: UncleYee | 来源:发表于2014-05-06 21:47 被阅读1407次

    索引是数据库中的一个重要对象,主要用于支持高效查询操作。如果没有索引,数据库就只能进行全表扫描,效率将极为低下。mongodb的索引体系比较庞大,按照索引类型,我准备分这么几个部分来进行阐述:

    • 基本索引

    • Text索引

    • GEO索引

    概述

    本文将简单介绍常用的基本索引类型,已经索引的相关操作。根据官方的文档,Mongodb有这么几种常见索引:

    • Default _id 主键索引,默认作用在_id

    • Single Field 单键索引,针对单个field的索引

    • Compound 复合索引,针对多个field的索引

    • Multikey Index,这个我都不知道怎么翻,多键索引吧,其实就是针对数组子项的索引,因为数组有多个元素,每个元素都可能的key,如果有一个索引A作用在这个key上,这就是所谓的Multikey index

    • Geospatial Index 针对地理位置信息的索引

    • Text Index 支持全文搜索的索引,2.4才支持

    • Hashed Index , To support hash based sharding, MongoDB provides a hashed index (page 22) type, which indexes the hash of the value of a field.

    同时,mongodb提供了两个索引的属性:

    • Unique 唯一性,保证索引作用的field上的value是唯一的。

    • Sparse 稀疏性,如果一个Collection中的某个field A 只存在于某些Document上,而 A 上同时建立了索引,那么用Sparse则会使查询操作直接忽略这些记录。

    好了,概念说了很多,来讲一下索引的具体操作吧。创建一个索引很简单,看看下面这些代码:

    
    // 单键索引
    db.Student.ensureIndex({code:1});
    
    // 复合索引
    db.Student.ensureIndex({name:1,time:-1})
    
    // Multikey Index
    db.Student.ensureIndex({faver.id:1});
    
    //  唯一索引
    db.Student.ensureIndex({code:1},{unique:1});
    
    // 唯一索引同时删除重复值
    db.Student.ensureIndex({code:1},{unique:1,dropDups:1});
    
    // 唯一稀疏索引
    db.Student.ensureIndex({code:1},{unique:1,sparse:1});
    
    
    

    获取一个Collection上面的集合信息

    // 单个Collection
    db.Student.getIndexes();
    
    // DB中所有的Index
    db.system.indexes.find();
    
    

    删除索引

    // 删除在某个field上面的索引
    db.Student.dropIndex({name:1});
    
    // 根据索引名删除
    db.system.indexes.remove({name:"code_-1"})
    
    

    如何修改索引呢?没有特定修改命令,一般是先删除,然后创建新的索引。

    系统运行一段时间以后,随着数据的累加,业务需求的变化,可能会需要对索引进行重建(rebuild),则可以做这个操作:

    db.collection.reIndex()
    

    rebuild会先删除集合上的所有索引,包括_id索引,然后重建。这种操作往往和耗时,最好在系统资源充足的时候做。

    细节

    1. 限制

    mongodb对索引的使用和管理也有一些限制

    • 索引key的总容量不能大于1024byte,否则以后的索引将创建不了

    • 单个集合不能超过64个索引

    • 单个索引的名字长度(包括命名空间)不能超过125 个字符

    • 复合索引最多只能作用在31个field上

    • 一个查询不能同时使用text and Geospatial 索引

    上面列的只是一些大的限制,在具体场景中还有很多索引相互冲突,或者使用不当造成索引无法命中的情况,所以还要看看更细节的一些东西。

    2. 使用策略

    2.1 _id 主键索引

    这个是系统自动创建的,不能删除,除非你Drop掉整个Collection。这个效率是非常高的,对于一些数据量很大,但是没有排序需求的集合(如日志表),在分页策略上应该使用_id来进行分页。

    2.2 single 单键索引

    mongodb 不限制你在任何field上面创建单键索引,但是一个查询一次只能使用一个索引($or子句可以使用多个),所以看看下面的情况会是这样的:

    //存在两个索引:
    {code:1},
    {name:1}
    
    //这里mongodb只会命中一个索引,具体是哪个由查询分析器决定
    db.Student.find({code:{$lt:10},name:{$regex:/^a/}}).explain();
    {
        "cursor" : "BtreeCursor name_1",
        "isMultiKey" : false,
        "n" : 1,
        "nscannedObjects" : 1,
        "nscanned" : 1,
        "nscannedObjectsAllPlans" : 4,
        "nscannedAllPlans" : 4,
        "scanAndOrder" : false,
        "indexOnly" : false,
        "nYields" : 0,
        "nChunkSkips" : 0,
        "millis" : 46,
        "indexBounds" : {
            "name" : [
                [
                    "a",
                    "b"
                ]
            ]
        },
        "server" : "pormatoMacBook-Pro.local:27017"
    }
    
    

    索引还存在排序问题,{a:1}升序 / {a:-1}降序,但是对于单键索引,排序的时候升序降序都会命中。如:

    db.Student.find().sort({name:1});
    db.Student.find().sort({name:-1});
    
    

    2.3 复合索引

    多数情况下,应该考虑复合索引而非单键索引,因为复合索引会包含部分单键索引。例如:
    对于索引:
    {a:1,b:1,c:1}
    相当于该集合拥有了:
    {a:1} , {a:1,b:1} , {a:1,b:1,c:1}
    但是:
    {b:1} ,{c:1} , {b:1,c:1} 是无法命中的。

    如果排序也希望命中索引的话,这里分为两种情况:

    • 排序字段以索引开始键开头
    // 因为查询条件中不存在索引开始键(a:1),要想命中索引,排序必须以索引开始键开头
    db.mycoll.find({b:{$gt:1}}).sort({a:1,b:1,c:1});
    
    • 排序字段不以索引开始键开头
    db.mycoll.find({a:{$gt:1}}).sort({b:1,c:1});
    

    当然,排序里面还有更为细致的问题,就是查询条件如果有索引field的精准匹配(equal),则排序也能更简单:

    db.mycoll.find({a:1}).sort({b:1});
    

    同样,复合索引也存在索引反序问题,这里和单键索引一样,只有完全反序才能命中:
    对于索引{a:1,b:-1}, {a:-1,b:1} 是可以命中的,反过来也成立。但是:{a:1,b:1}或者{a:-1,b:-1}是无法命中索引的。

    3 MultiKey Index 多键索引

    多键索引是作用在 array field上的element中的某个field上的索引。这个没有太多的特别之处,唯一要注意的是,如果一个索引是复合多键索引,那么这个索引的field中只能有一个array类型。例如:
    {a:1,b:[{b1:1,b2:1}] 这个是Ok的, {a:[a1:1,a2:1],b:[{b1:1,b2:1}] 这种索引则是非法的。

    其它

    mongdb中还存在一种Cover Index的说法。它发生在如下的情况中:

    • all the fields in the query are part of an index, and

    • all the fields returned in the results are in the same index.

    代码

    
    db.mycoll.find({a:{$lt:100}},{a:1,_id:0}});
    
    

    这个时候查询条件的field和 查询域field 完全一样,并且这个field刚好能命中索引的话,这个查询效率将非常的高,因为mongodb不会再去硬盘进行扫描,而是直接将Index信息返回。

    这里需要知道的是如果在下面两种情况下,Cover Index将无法生效

    • any of the indexed fields in any of the documents in the collection includes an array. If an indexed field is an array, the index becomes a multi-key index , index and cannot support a covered query.
      数组field将直接会使索引变为多键索引

    • any of the indexed fields are fields in subdocuments. To index fields in subdocuments, use dot notation.
      查询域总是会返回整个子文档的root节点

    基本的索引类型就是这么多了,接下来还有Text , Geo ,hash等较为复杂的索引类型,这个在以后的文章中再来分析。

    相关文章

      网友评论

        本文标题:Mongodb索引探索(一)

        本文链接:https://www.haomeiwen.com/subject/kfprtttx.html