初识MongoDB中的索引

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

本文是MongoDB系列的第九篇文章,了解前面的文章有助于更好的理解本文。


索引创建

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

db.sang_collect.getIndexes()

结果如下:

[
    {
        "v" : 2,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_",
        "ns" : "sang.sang_collect"
    }
]

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

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

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

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

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

结果如下:

{
    "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,如下:

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

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

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

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

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

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

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

[
    {
        "v" : 2,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_",
        "ns" : "sang.sang_collect"
    },
    {
        "v" : 2,
        "key" : {
            "x" : 1.0
        },
        "name" : "x_1",
        "ns" : "sang.sang_collect"
    }
]

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

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

此时创建好的索引如下:

{
    "v" : 2,
    "key" : {
        "x" : 1.0
    },
    "name" : "myfirstindex",
    "ns" : "sang.sang_collect"
}

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

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表示索引的权重

此时创建好的索引如下:

{
    "v" : 1,
    "unique" : true,
    "key" : {
        "x" : 1.0
    },
    "name" : "myfirstindex",
    "ns" : "sang.sang_collect",
    "background" : true,
    "sparse" : true,
    "weights" : 99999.0
}

查看索引

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

db.sang_collect.totalIndexSize()

删除索引

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

db.sang_collect.dropIndex("xIndex")

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

db.sang_collect.dropIndexes()

总结

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

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

参考资料:

1.《MongoDB权威指南第2版》

原文发布于微信公众号 - 玩转JavaEE(gh_d1ca11234a30)

原文发表时间:2017-12-01

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏农夫安全

注入学习之sqli-labs-3(第二关)

前言 本来是想一个个关卡讲下去,后来自己测试了一下,发现第二、三、四这三关跟第一关,起始原理是一样的,只不过是单引号,双引号,带不带括号的区别,只要我们带入的语...

3416
来自专栏Java面试通关手册

Mysql锁机制简单了解一下

Java面试通关手册(Java学习指南,欢迎Star,会一直完善下去,欢迎建议和指导):https://github.com/Snailclimb/Java_G...

16811
来自专栏Java技术交流群809340374

MySQL有哪些存储引擎,各自的优缺点,应用场景

经常面试都会问到MYSQL有哪些存储引擎,以及各自的优缺点。今天主要分享常见的存储引擎:MyISAM、InnoDB、MERGE、MEMORY(HEAP)、BDB...

2333
来自专栏跟着阿笨一起玩NET

Server 2005中的分区表(一)

本文转载:http://blog.csdn.net/smallfools/article/details/4930810

772
来自专栏技术沉淀

Python: 操作MySQL数据库

1974
来自专栏企鹅号快讯

从商用到开源:15个维度,全面剖析DB2与MySQL数据库的差异

编辑手记 MySQL是目前最流行的开源数据库,由于其部署方便,运维简单,被广泛用于互联网的各个领域。随着整体IT架构的变更,传统的金融,电信业务,也逐渐走上从商...

2399
来自专栏杨建荣的学习笔记

MySQL 5.7 General Tablespace学习(r11笔记第34天)

MySQL里面的文件蛮有意思,之前大体有两个参数来做基本的控制。一个是innodb_data_file_path就是一个共享表空间,数据都往这一个文件里放,也就...

3819
来自专栏我和PYTHON有个约会

数据库连接引擎那点事儿

天长,地久。天地之所以能长且久者,以其不自生也,故能长生。是以圣人后其身而身先,外其身而身存,非以其无私邪?故能成其私。——老子

912
来自专栏用户画像

mysql 模拟试题一

  3.SQL语言的数据操纵语句包括 SELECT,INSERT,UPDATE和 DELETE, 最重要的,也是使用最频繁的语句是__A__。 

1374
来自专栏王磊的博客

Microsoft SQL Server 2005 提供了一些工具来监控数据库

--WL 09-07-03 /*Microsoft SQL Server 2005 提供了一些工具来监控数据库。方法之一是动态管理视图。动态管理视图 (DMV)...

3515

扫码关注云+社区

领取腾讯云代金券