zoukankan      html  css  js  c++  java
  • MongoDB 学习五:索引

    这章我们介绍MongoDB的索引,用来优化查询。

    索引介绍

    数据库索引有些类似书的目录。

    一个查询如果没有使用索引被称为表扫描,意思是它必须像阅读整本书那样去获取一个查询结果。一般来说,我们应尽量避免这种情况,

    因为它是非常慢的。

    举个例子,我们创建一个百万条数据的collection:

    for(i=0;i<1000000;i++){
         db.users.insert({
              "i":i,
              "username":"user" + i,
              "age":Math.floor(Math.random()*120),
              "created":new Date()
       })
    }

    假如我们查找这个collection,我们可以使用explain()来查看详细的查询信息。例如:

    db.users.find({username:"user101"}).explain();

    返回

    {
            "cursor" : "BasicCursor",
            "isMultiKey" : false,
            "n" : 1,
            "nscannedObjects" : 1000000,
            "nscanned" : 1000000,
            "nscannedObjectsAllPlans" : 1000000,
            "nscannedAllPlans" : 1000000,
            "scanAndOrder" : false,
            "indexOnly" : false,
            "nYields" : 7812,
            "nChunkSkips" : 0,
            "millis" : 521,
            "server" : "Colin_xu:27017",
            "filterSet" : false
    }

    上述信息要点:

    "cursor":"BasicCursor"说明查询没有使用索引

    "nscanned":1000000   代表查询了多少文档

    "n":1   代表返回文档的数量

    "millis":521 代表数据库执行查询的时间(毫秒)

    这时我们加上索引:

    db.user.ensureIndex({"username":1})

    这时再查询的返回结果:

    {
            "cursor" : "BtreeCursor username_1",
            "isMultiKey" : false,
            "n" : 1,
            "nscannedObjects" : 1,
            "nscanned" : 1,
            "nscannedObjectsAllPlans" : 1,
            "nscannedAllPlans" : 1,
            "scanAndOrder" : false,
            "indexOnly" : false,
            "nYields" : 0,
            "nChunkSkips" : 0,
            "millis" : 47,
            "indexBounds" : {
                    "username" : [
                            [
                                    "user101",
                                    "user101"
                            ]
                    ]
            },
            "server" : "Colin_xu:27017",
            "filterSet" : false
    }

    这时我们看看两次结果的misllis,差距显而易见。

    复合索引

    当查询中排序中仅使用一个键时,可以对该键建立索引,以提高查询速度。然而,对于其他查询可能没有帮助,即便是查询包含了被索引的键。

    所以,一定要创建查询中用到所有键的索引。

    索引名称

    集合中的每个索引都有一个字符串类型的名字,来唯一标识索引,服务器通过这个名字来删除或者操作索引。

    默认情况下,索引名类似keyname1_dir1_keyname2_dir2_..._keynameN_dirN这种形式,其中keynameX代表索引的键,

    dirX代表索引的方向(1或者-1)。要是索引的键特别多,这样命名就略显愚笨,不过还好可以通过ensureIndex的选项来自定义名字。

    db.foo.ensureIndex({"a":1,"b":1,"c":1,...,"z":1},{"name":"alphabet"})

    索引名有字符个数的限制,所以特别复杂的索引在创建时一定要用自定义名字。

    唯一索引

    唯一索引可以确保集合的每一个文档的指定键都有唯一值。例如,如果想保证文档的"username"键都有不一样的值,创建一个唯一索引就好了:

    db.users.ensureIndex({"username":1},{"unique":true});

    消除重复

    当为已有的集合创建索引,可能有些值已经有重复了。若是真的发生这种情况,那么索引的创建就是失败。有些时候,可能希望将所有包含重复值的文档都删掉。

    dropDups选项就可以保留发现的第一个文档,而删除接下来的有重复值的文档:

    db.people.ensureIndex({"username":1},{"unique":true,"dropDups":true})

    地理空间索引

    还有一种查询变得越来越流行(尤其是随着移动设备的出现);找到离当前位置最近的N个场所。MongoDB为坐标平面查询提供了专门的索引,称为地理空间索引。

    假设要找到给定经纬度周围最近的咖啡馆,就需要创建一个专门的索引来提高这种查询的效率,这是因为这种查询需要搜索两个维度。地理空间索引同样可以由ensureIndex来创建,

    只不过参数不是1,而是"2d";

    db.map.ensureIndex({"gps":"2d"})

    "gps"键的值必须是某种形式的一对值:一个包含两个元素的数组或是包含两个键的内嵌文档。下面这些都是有效的:

    {"gps":[0,100]};
    
    {"gps":{"x":-30,"y":30}};
    
    {"gps":{"latitude":-180,"longitude":180}};

    至于键名可以随意。

    地理空间查询以两种方式进行,即普通查询或者使用数据库命令。find的方式与一般的查询差别不大,只不过用了"$near"。需要两个目标值的数组作为参数:

    db.map.find({"gps":{"$near":[40,-73]}})

    这会按照离点(40,-73)由近及远的方式将map集合的所有文档都返回。在没有指定limit的值时,默认是100个文档。

    也可以使用geoNear来完成相同操作。

    db.runCommond({"geoNear”:"map","near":[40,-73]})

    geoNear还会返回每个文档到查询点的距离,这个距离是以你插入的数据为单位的,如果按照经纬度的角度插入,则距离就是经纬度。

    find和"$near"的组合不会给出距离,但若结果大于4M,这是唯一的选择。

  • 相关阅读:
    Unity3D之Mesh【创建动态Mesh的学习网站】
    Unity3D之Mesh(三)绘制四边形
    Unity3D之Mesh(二)为三角形添加纹理
    unity的一些重要技巧(转)【整理他人的东西】
    Unity3D之Mesh(一)绘制三角形
    Unity3D连接WCF
    zabbix server搭建遇到的问题
    zabbix server for Centos 6.3
    JAVA笔记整理(九),JAVA中的集合
    MySQL主从复制(Centos6.3&MySQL5.6)
  • 原文地址:https://www.cnblogs.com/showtime813/p/4863990.html
Copyright © 2011-2022 走看看