MongoDB性能优化——组合索引


  • Lv 1

    1、概述

    • MongoDB索引信息被保存在system.indexes 中,一个索引的好坏直接影响着查询性能。MongoDB 提供了多样性的索引支持,默认总是为_id创建索引,它的索引使用基本和关系型数据库一样,MongoDB 也是有组合索引的。当创建组合索引时,字段后面的1 表示升序,-1 表示降序,是用1 还是用-1 主要是跟排序或指定范围内查询的时候有关。

    2、创建组合索引优化的过程

    • 首先创建测试数据
    MongoDB Enterprise testrs:PRIMARY> db.employee.find()
    { "_id" : ObjectId("58257af29f90f52f285af4b2"), "emp_name" : "plant", "age" : "21", "sex" : "1", "emp_no" : "1" }
    { "_id" : ObjectId("58257b129f90f52f285af4b3"), "emp_name" : "jason", "age" : "22", "sex" : "1", "emp_no" : "2" }
    { "_id" : ObjectId("58257b289f90f52f285af4b4"), "emp_name" : "ambern", "age" : "23", "sex" : "0", "emp_no" : "3" }
    { "_id" : ObjectId("58257b479f90f52f285af4b5"), "emp_name" : "henry", "age" : "24", "sex" : "1", "emp_no" : "4" }
    MongoDB Enterprise testrs:PRIMARY>
    
    • 在创建组合索引之前我们先通过explain()对索引进行考量
      a.范围查询
    db.employee.find({"$and":[{"age":{"$gte":"22"}},{"age":{"$lte":"24"}}]}).explain()
    {  
        "cursor" : "BasicCursor",  
        "n" : 3,  
        "nscannedObjects" : 4,  
        "nscanned" : 4,  
        "scanAndOrder" : true 
    } 
    

    “BasicCursor”它意味着MongoDB将对数据集做一个完全的扫描,当数据集里包含上千万条信息时,这完全是行不通的。所以这里需要在age上加一个索引:

    MongoDB Enterprise testrs:PRIMARY> db.employee.createIndex({"age":1})
    {
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
    }
    

    现在再看explain()的输出结果:

    {  
        "cursor" : "BtreeCursor age_1",  
        "n" : 3,  
        "nscannedObjects" : 3,  
        "nscanned" : 3,  
        "scanAndOrder" : false 
    } 
    

    现在cursor的类型明显变成了“BtreeCursor",而且nscanned从4降到了3

    b.范围查询的基础上添加等值查询

    MongoDB Enterprise testrs:PRIMARY> db.employee.find({"$and":[{"$and":[{"age":{"$gte":"22"}},{"age":{"$lte":"24"}}]},{"sex":"0"}]})
    { "_id" : ObjectId("58257b289f90f52f285af4b4"), "emp_name" : "ambern", "age" : "23", "sex" : "0", "emp_no" : "3" }
    MongoDB Enterprise testrs:PRIMARY>
    

    现在再看explain()的输出结果:

    db.employee.find({"$and":[{"$and":[{"age":{"$gte":"22"}},{"age":{"$lte":"24"}}]},{"sex":"0"}]}).explain()
    {  
        "cursor" : "BtreeCursor age_1",  
        "n" : 2,  
        "nscannedObjects" : 3,  
        "nscanned" : 3,  
        "scanAndOrder" : false 
    } 
    

    从explain()输出结果上来看:虽然n从3降到了2,但是nscanned和nscannedObjects的值仍然为3

    • 创建组合索引
    MongoDB Enterprise testrs:PRIMARY> db.employee.createIndex({"age":1,"sex":1})
    {
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 2,
        "numIndexesAfter" : 3,
        "ok" : 1
    }
    

    再查看explain()的输出结果:

    {  
        "cursor" : "BtreeCursor age_1_sex_1",  
        "n" : 2,  
        "nscannedObjects" : 2,  
        "nscanned" : 3,  
        "scanAndOrder" : false 
    } 
    

    这次的情况好了一点:nscannedObjects从3降到了2

    3、字段说明
    cursor:返回游标类型,有BasicCursor和BtreeCursor,后者意味着使用了索引
    nscanned:扫描文档的行数
    nscannedObjects :扫描对象的个数
    n:返回的文档行数
    millis:耗时(毫秒)
    scanAndOrder :是否在内存中对结果集进行了排序

    4、小结

    • MongoDB的索引是在collection级别上的,创建适当的索引才能优化我们的查询性能,只要查询和索引匹配,就能利用索引,所以创建索引时要考虑这些查询依赖的所有字段,并且根据各个字段查询的频率定义索引字段顺序。

登录后回复
 

与 萌阔论坛 的连接断开,我们正在尝试重连,请耐心等待