MongoDB索引的学习笔记

一、索引基础:

MongoDB的索引几乎与传统的关系型数据库一模一样,这其中也包括一些基本的优化技巧。下面是创建索引的命令:
> db.test.ensureIndex({“username”:1})
可以通过下面的名称查看索引是否已经成功建立:
> db.test.getIndexes()
删除索引的命令是:
> db.test.dropIndex({“username”:1})
在MongoDB中,我们同样可以创建复合索引,如:
— 数字1表示username键的索引按升序存储,-1表示age键的索引按照降序方式存储。
> db.test.ensureIndex({“username”:1, “age”:-1})
该索引被创建后,基于username和age的查询将会用到该索引,或者是基于username的查询也会用到该索引,但是只是基于age的查询将不会用到该复合索引。因此可以说,如果想用到复合索引,必须在查询条件中包含复合索引中的前N个索引列。然而如果查询条件中的键值顺序和复合索引中的创建顺序不一致的话,MongoDB可以智能的帮助我们调整该顺序,以便使复合索引可以为查询所用。如:
> db.test.find({“age”: 30, “username”: “stephen”})
对于上面示例中的查询条件,MongoDB在检索之前将会动态的调整查询条件文档的顺序,以使该查询可以用到刚刚创建的复合索引。
我们可以为内嵌文档创建索引,其规则和普通文档没有任何差别,如:
> db.test.ensureIndex({“comments.date”:1})
对于上面创建的索引,MongoDB都会根据索引的keyname和索引方向为新创建的索引自动分配一个索引名,下面的命令可以在创建索引时为其指定索引名,如:
> db.test.ensureIndex({“username”:1},{“name”:”testindex”})
随着集合的增长,需要针对查询中大量的排序做索引。如果没有对索引的键调用sort,MongoDB需要将所有数据提取到内存并排序。因此在做无索引排序时,如果数据量过大以致无法在内存中进行排序,此时MongoDB将会报错。

二、唯一索引:

在缺省情况下创建的索引均不是唯一索引。下面的示例将创建唯一索引,如:
> db.test.ensureIndex({“userid”:1},{“unique”:true})
如果再次插入userid重复的文档时,MongoDB将报错,以提示插入重复键,如:
> db.test.insert({“userid”:5})
> db.test.insert({“userid”:5})
E11000 duplicate key error index: test.test.$userid_1 dup key: { : 5.0 }
如果插入的文档中不包含userid键,那么该文档中该键的值为null,如果多次插入类似的文档,MongoDB将会报出同样的错误,如:
> db.test.insert({“userid1″:5})
> db.test.insert({“userid1″:5})
E11000 duplicate key error index: test.test.$userid_1 dup key: { : null }
如果在创建唯一索引时已经存在了重复项,我们可以通过下面的命令帮助我们在创建唯一索引时消除重复文档,仅保留发现的第一个文档,如:
–先删除刚刚创建的唯一索引。
> db.test.dropIndex({“userid”:1})
–插入测试数据,以保证集合中有重复键存在。
> db.test.remove()
> db.test.insert({“userid”:5})
> db.test.insert({“userid”:5})
–创建唯一索引,并消除重复数据。
> db.test.ensureIndex({“userid”:1},{“unique”:true,”dropDups”:true})
–查询结果确认,重复的键确实在创建索引时已经被删除。
> db.test.find()
{ “_id” : ObjectId(“4fe823c180144abd15acd52e”), “userid” : 5 }

我们同样可以创建复合唯一索引,即保证复合键值唯一即可。如:
> db.test.ensureIndex({“userid”:1,”age”:1},{“unique”:true})

 

三、松散索引

如果你的数据中一些行中没有某个字段或字段值为null,那么如果在这个字段上建立普通索引,那么无此字段或值null的行也会参与到索引结构中,占用相应的空间。如果我们不希望这些值为空的行参与到我们的索引中,这时候可以采用松散索引,松散索引只会让指定字段不为空的行参与到索引创建中来。创建一个松散索引可以用下面的命令:

db.reviews.ensureIndex({user_id: 1}, {sparse: true})

四、多值索引

MongoDB可以对一个array类型创建索引,比如像下面的结构,MongoDB可以在tags字段上创建索引:

{ name: "Wheelbarrow",

    tags: ["tools", "gardening", "soil"]

}

在生成索引时,会为tags中的三个值分别生成三个索引元素,索引中tools,gardening,soil三个值都会指向这同一行数据。相当于分裂成了三个独立的索引项。

三、使用explain:

explain是非常有用的工具,会帮助你获得查询方面诸多有用的信息。只要对游标调用该方法,就可以得到查询细节。explain会返回一个文档,而不是游标本身。如:www.111cn.net
> db.test.find().explain()
{
“cursor” : “BasicCursor”,
“nscanned” : 1,
“nscannedObjects” : 1,
“n” : 1,
“millis” : 0,
“nYields” : 0,
“nChunkSkips” : 0,
“isMultiKey” : false,
“indexOnly” : false,
“indexBounds” : {

}
}
explain会返回查询使用的索引情况,耗时和扫描文档数的统计信息。
“cursor”:”BasicCursor”表示没有使用索引。
“nscanned”:1 表示查询了多少个文档。
“n”:1 表示返回的文档数量。
“millis”:0 表示整个查询的耗时。

四、索引管理:

system.indexes集合中包含了每个索引的详细信息,因此可以通过下面的命令查询已经存在的索引,如:
> db.system.indexes.find()
如果在为已有数据的文档创建索引时,可以执行下面的命令,以使MongoDB在后台创建索引,这样的创建时就不会阻塞其他操作。但是相比而言,以阻塞方式创建索引,会使整个创建过程效率更高,但是在创建时MongoDB将无法接收其他的操作。
> db.test.ensureIndex({“username”:1},{“background”:true})

创建索引命令

实际上创建索引还有更方便的命令,那就是ensureIndex,比如我们创建一个open和close两个字段的联合索引,就可以用下面的命令:

db.values.ensureIndex({open: 1, close: 1})

这个命令会触发索引创建的两个过程,一个是将相应的字段排序,因为索引是按B+树来组织的,要构建树,将数据进行排序后能够提高插入B+树的效率(第二个过程的效率),在日志中,你能看到和下面类似的输出:

Tue Jan 4 09:58:17 [conn1] building new index on { open: 1.0, close: 1.0 } for stocks.values

1000000/4308303 23%

2000000/4308303 46%

3000000/4308303 69%

4000000/4308303 92%

Tue Jan 4 09:59:13 [conn1] external sort used : 5 files in 55 secs

第二个过程是将排序好的数据插入到索引结构中,构成可用的索引:

1200300/4308303 27%

2227900/4308303 51%

2837100/4308303 65%

3278100/4308303 76%

3783300/4308303 87%

4075500/4308303 94%

Tue Jan 4 10:00:16 [conn1] done building bottom layer, going to commit

Tue Jan 4 10:00:16 [conn1] done for 4308303 records 118.942secs

Tue Jan 4 10:00:16 [conn1] insert stocks.system.indexes 118942ms

除了日志中的输出外,你还可以通过在终端执行currentOp命令来获取当前操作线程的相关信息,如下例:

> db.currentOp()

{

    "inprog" : [

        {

             "opid" : 58,

             "active" : true,

             "lockType" : "write",

             "waitingForLock" : false,

             "secs_running" : 55,

             "op" : "insert",

             "ns" : "stocks.system.indexes",

             "query" : {

         },

         "client" : "127.0.0.1:53421",

         "desc" : "conn",

         "msg" : "index: (1/3) external sort 3999999/4308303 92%"

     }

    ]

}

最后一部分就是一个索引构建过程,目前正在执行排序过程,执行到92%。

在后台创建索引 www.111cn.net

创建索引会对数据库添加写锁,如果数据集比如大,会将线上读写数据库的操作挂起,以等待索引创建结束。这影响了数据库的正常服务,我们可以通过在创建索引时加background:true 的选项,让创建工作在后台执行,这时候创建索引还是需要加写锁,但是这个写锁不会直接独占到索引创建完成,而是会暂停为其它读写操作让路,不至于造成严重的性能影响。具体方法:

db.values.ensureIndex({open: 1, close: 1}, {background: true})

离线创建索引

无论如何,索引的创建都会给数据库造成一定的压力,从而影响线上服务。如果希望创建索引的过程完全不影响线上服务,我们可以通过将replica sets中的节点先从集群中剥离,在这个节点上添加相应的索引,等索引添加完毕后再将其添加到replica sets中。这只需要保证一个条件,就是创建索引的时间不能长于oplog能够保存日志的时间,否则创建完后节点再上线发现再也无法追上primary了,这时会进行resync操作。

索引备份

我们知道,无论是使用mongodump还是mongoexport命令,都只是对数据进行备份,无法备份索引。我们在恢复的时候,还是需要等待漫长的索引创建过程。所以,如果你希望备份的时候带上索引,那么最好采用备份数据文件的方式。

索引压缩

索引在使用一段时间后,经历增删改等操作,会变得比较松散,从而战用不必要的空间,我们可以通过reindex命令,重新组织索引,让索引的空间占用变得更小。

时间: 2024-10-26 04:26:48

MongoDB索引的学习笔记的相关文章

PHP操作MongoDB配置与学习笔记

PHP操作MongoDB配置与学习笔记有需要的朋友可参考参考.Mongo主要解决的是海量数据的访问效率问题,根据官方的文档,当数据量达到50GB以上的时候,Mongo的数据库访问速度是MySQL的 10倍以上 2,安装(windows only) 到官网下载对应的包 解压到d:mongodb 创建d:mongodbdata放置数据文件 3,运行mongodb d:mongodbbin下有一些可执行文件,其中mongod.exe是服务器端,mongo.exe是客户端. 运行cmd,输入 d:mon

2.myql数据导入到solr,并建立solr索引(学习笔记)

1.1     业务域名的配置 1.1.1   需求 要使用solr实现电商网站中商品搜索. 电商中商品信息在mysql数据库中存储了,将mysql数据库中数据在solr中创建索引. 需要在solr的schema.xml文件定义商品Field. 1.1.2   定义步骤 在schema.xml中配置域   商品id(pid) 这是商品的主键,由于schema文件中已经有主键id了就不需要对它配置了 <field name="id"type="string" i

MySQL索引操作命令学习笔记

mysq索引类型:普通索引.唯一索引和主索引 1. 普通索引 普通索引(由关键字KEY或INDEX定义的索引)的唯一任务是加快对数据的访问速度.因此,应该只为那些最经常出现在查询条件(WHERE column = -)或排序条件(ORDER BY column)中的数据列创建索引.只要有可能,就应该选择一个数据最整齐.最紧凑的数据列(如一个整数类型的数据列)来创建索引. 2. 唯一索引 普通索引允许被索引的数据列包含重复的值.比如说,因为人有可能同名,所以同一个姓名在同一个"员工个人资料&quo

php数组的索引的学习笔记

存储在数组中的值被称为数组元素,每个数组元素有一个相关的引索(也称为关键字),可以用来访问元素.PHP允许间隔性的使用数字或字符串作为数组的引索.使用字符串作为引索更具有意义和便于使用. 数字索引数组 创建一个数组可以使用如下代码: $num = array(1, 2, 3, 4, 5, 6);   以上代码会创建一个名为 $num 的数组,包含数字从1-6,array() 是一个语言结构,而不是函数. 如果需要按照升序排列数字保存在一个数组中,可以使用 range()函数自动创建这个数组. $

Mysql学习笔记(八)索引

原文:Mysql学习笔记(八)索引 PS:把昨天的学习内容补上...发一下昨天学的东西....五月三日...继续学习数据库... 学习内容: 索引.... 索引的优点: 1.通过创建唯一索引,可以保证数据库每行数据的唯一性... 2.使查找的速度明显加快... 3.当使用分组和排序进行查询时,可以缩短时间... 索引的缺点: 1.维护索引需要耗费数据库的资源... 2.索引需要占用磁盘空间... 3.对表进行增删改的时候,由于索引的存在,时间会有所增加... 索引的分类... 普通索引和唯一索引

Mysql学习笔记(九)索引查询优化

原文:Mysql学习笔记(九)索引查询优化 PS:上网再次看了一下数据库关于索引的一些细节...感觉自己学的东西有点少...又再次的啃了啃索引.... 学习内容: 索引查询优化... 上一章说道的索引还不是特别的详细,再补充一些具体的细节... 1.B-Tree索引... B-tree结构被称为平衡多路查找树...其数据结构为:     这就是其数据结构图...我们没必要完全的理解其中的原理..并且我也不会做过多的原理介绍...我们只需要知道数据库是以这种方式进行存储数据的就可以了...   m

分区索引学习笔记

续接上次的分区表学习笔记,对分区索引进行了总结. --index maintance SQL> select index_name,table_name from user_indexes where table_name='RANGE_PART'; no rows selected --create one global index SQL> create index glb_range_part on range_part(a,b)   2  global partition by ran

PL/SQL学习笔记(索引贴)

我前段时间写了T-SQL学习笔记得到了许多朋友的支持当然也有一些朋友提出了质疑,在此一并表示感谢最近项目中用到Oracle,于是萌生了写PL/SQL学习笔记的念头.同时也希望得到大家的支持或批评.并非常希望能和朋友们一起讨论相关知识. 这是一个有一点T-SQL基础的.刚入门者的学习笔记,以Oracle  10g为讲解对象没有涉及到高级话题如果对哪篇文章有疑问,可以在文章下留言我会尽快回复的 下面我为这个系列文章做一个索引 一: 常量变量及数据类型初步       1:常量变量       2:数

Ruby学习笔记_索引贴

学习Ruby也有段时间了,在学习的同时也做了些笔记并发到了园子睐.看到园子里的大虾们在出了一系列文章后都会做个索引贴,这样很方便,所以本人今天抽了个空就把它整理了下,方便自己的同时也方便感兴趣的朋友.   Ruby学习笔记目录: 1.Ruby入门 2.Ruby-循环与选择结构 3.Ruby-String 4.Ruby-Array 5.Ruby-Hash 6.Ruby-Block, Proc and Lambda 7.Ruby-正则表达式 8.Ruby-Symbol 9.Ruby-Method,C