• MongoDB学习笔记(六)


    初识 MongoDB 中的索引

    索引就像图书的目录一样,可以让我们快速定位到需要的内容,关系型数据库中有索引,NoSQL 中当然也有,本文我们就先来简单介绍下 MongoDB 中的索引。

    索引创建

    默认情况下,集合中的 _id 字段就是索引,我们可以通过 getIndexes() 方法来查看一个集合中的索引:

    1
    db.sang_collect.getIndexes()

    结果如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [
    {
    "v" : 2,
    "key" : {
    "_id" : 1
    },
    "name" : "_id_",
    "ns" : "sang.sang_collect"
    }
    ]

    我们看到这里只有一个索引,就是 _id

    现在我的集合中有 10000 个文档,我想要查询 x 为 1 的文档,我的查询操作如下:

    1
    db.sang_collect.find({x:1})

    这种查询默认情况下会做全表扫描,我们可以用上篇文章介绍的 explain() 来查看一下查询计划,如下:

    1
    db.sang_collect.find({x:1}).explain("executionStats")

    结果如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    {
    "queryPlanner" : {
    },
    "executionStats" : {
    "executionSuccess" : true,
    "nReturned" : 1,
    "executionTimeMillis" : 15,
    "totalKeysExamined" : 0,
    "totalDocsExamined" : 10000,
    "executionStages" : {
    "stage" : "COLLSCAN",
    "filter" : {
    "x" : {
    "$eq" : 1.0
    }
    },
    "nReturned" : 1,
    "executionTimeMillisEstimate" : 29,
    "works" : 10002,
    "advanced" : 1,
    "needTime" : 10000,
    "needYield" : 0,
    "saveState" : 78,
    "restoreState" : 78,
    "isEOF" : 1,
    "invalidates" : 0,
    "direction" : "forward",
    "docsExamined" : 10000
    }
    },
    "serverInfo" : {
    },
    "ok" : 1.0
    }

    结果比较长,我摘取了关键的一部分。我们可以看到查询方式是全表扫描,一共扫描了 10000 个文档才查出来我要的结果。实际上我要的文档就排第二个,但是系统不知道这个集合中一共有多少个 x 为 1 的文档,所以会把全表扫描完,这种方式当然很低效,但是如果我加上 limit,如下:

    1
    db.sang_collect.find({x:1}).limit(1)

    此时再看查询计划发现只扫描了两个文档就有结果了,但是如果我要查询 x 为 9999 的记录,那还是得把全表扫描一遍,此时,我们就可以给该字段建立索引,索引建立方式如下:

    1
    db.sang_collect.ensureIndex({x:1})

    1 表示升序,-1 表示降序。当我们给 x 字段建立索引之后,再根据 x 字段去查询,速度就非常快了,我们看下面这个查询操作的执行计划:

    1
    db.sang_collect.find({x:9999}).explain("executionStats")

    这个查询计划过长我就不贴出来了,我们可以重点关注查询要耗费的时间大幅度下降。

    此时调用 getIndexes() 方法可以看到我们刚刚创建的索引,如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    [
    {
    "v" : 2,
    "key" : {
    "_id" : 1
    },
    "name" : "_id_",
    "ns" : "sang.sang_collect"
    },
    {
    "v" : 2,
    "key" : {
    "x" : 1.0
    },
    "name" : "x_1",
    "ns" : "sang.sang_collect"
    }
    ]

    我们看到每个索引都有一个名字,默认的索引名字为 字段名_排序值,当然我们也可以在创建索引时自定义索引名字,如下:

    1
    db.sang_collect.ensureIndex({x:1},{name:"myfirstindex"})

    此时创建好的索引如下:

    1
    2
    3
    4
    5
    6
    7
    8
    {
    "v" : 2,
    "key" : {
    "x" : 1.0
    },
    "name" : "myfirstindex",
    "ns" : "sang.sang_collect"
    }

    当然索引在创建的过程中还有许多其他可选参数,如下:

    1
    db.sang_collect.ensureIndex({x:1},{name:"myfirstindex",dropDups:true,background:true,unique:true,sparse:true,v:1,weights:99999})

    关于这里的参数,我说一下:

    1. name 表示索引的名称
    2. dropDups 表示创建唯一性索引时如果出现重复,则将重复的删除,只保留第一个
    3. background 是否在后台创建索引,在后台创建索引不影响数据库当前的操作,默认为 false
    4. unique 是否创建唯一索引,默认 false
    5. sparse 对文档中不存在的字段是否不起用索引,默认 false
    6. v 表示索引的版本号,默认为 2
    7. weights 表示索引的权重

    此时创建好的索引如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    {
    "v" : 1,
    "unique" : true,
    "key" : {
    "x" : 1.0
    },
    "name" : "myfirstindex",
    "ns" : "sang.sang_collect",
    "background" : true,
    "sparse" : true,
    "weights" : 99999.0
    }

    查看索引

    上文我们介绍了 getIndexes() 可以用来查看索引,我们还可以通过 totalIndexSize() 来查看索引的大小,如下:

    1
    db.sang_collect.totalIndexSize()

    删除索引

    我们可以按名称删除索引,如下:

    1
    db.sang_collect.dropIndex("xIndex")

    表示删除一个名为xIndex的索引,当然我们也可以删除所有索引,如下:

    1
    db.sang_collect.dropIndexes()

    总结

    索引是个好东西,可以有效的提高查询速度,但是索引会降低插入、更新和删除的速度,因为这些操作不仅要更新文档,还要更新索引,MongoDB 限制每个集合上最多有 64 个索引,我们在创建索引时要仔细斟酌索引的字段。

    好了,MongoDB 中的索引入门我们就说到这里,小伙伴们有问题欢迎留言讨论。

    参考资料:

    1. 《MongoDB权威指南第2版》
  • 相关阅读:
    Node.js 函数
    Node.js模块系统
    在Apache服务器上安装SSL证书
    Node.js Stream(流)--文件操作
    HTML5自带验证美化
    HTML5约束验证API
    Node.js Buffer(缓冲区)
    Python 练习:简单的购物车(二)
    Python 练习:简单的购物车
    Python 列表操作
  • 原文地址:https://www.cnblogs.com/eer123/p/11734081.html
Copyright © 2020-2023  润新知