博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
MongoDB入门学习(四):MongoDB的索引
阅读量:5332 次
发布时间:2019-06-14

本文共 6413 字,大约阅读时间需要 21 分钟。

        讲到了MongoDB的基本操作增删查改。对于查询来说。必须依照我们的查询要求去集合中,并将查找到的结果返回。在这个过程中事实上是对整个集合中每一个文档进行了扫描,假设满足我们的要求就加入到结果集中最后返回。对于小集合来说。这个过程没什么,可是集合中数据非常大的时候,进行表扫描是一个非常恐怖的事情,于是有了索引一说,索引是用来加速查询的。相当于书籍的文件夹。有了文件夹能够非常精准的定位要查找内容的位置,从而降低无谓的查找。

1.索引的类型

        创建索引能够是在单个字段上,也能够是在多个字段上,这个依据自己的实际情况来选择,创建索引时字段的顺序也是有讲究的。

创建索引是通过ensureIndex()方法。须要给该方法传递一个文档形式的数据,当中指定索引的字段和顺序,1代表升序。-1代表降序。

        1).默认索引

           还记得"_id"吗,这个字段的数据是不能反复的。它就是MongoDB的默认索引。并且不能被删除。

        2).单列索引

           在单个字段上创建的索引就是单列索引,在查询的过程中能够对该加速对该键的查询,然而对其它键的查询是没有帮助的。

单列索引的顺序是不会影响对该键的随即查询。创建单列索引:

> db.people.ensureIndex({"name" : 1})

        3).组合索引

           还能够在多个键上创建组合索引,此时键的位置和索引的顺序都会影响查询的效率。看以下创建组合索引:

> db.people.ensureIndex({"name" : 1, "age" : 1})> db.people.ensureIndex({"age" : 1, "name" : 1})

           第一种情况会对name排序组织,当name一样时在对age排序,所以对{"name" : 1}和{“name” : 1, "age" : 1}的查询更高效,而另外一种情况则对age排序。当age一样再对name排序。所以对{"age" : 1}和{"age" : 1, "name" : 1}的查询更高效。当组合索引包括非常多字段的时候。会对前几个键的查询有帮助。

        4).内嵌文档索引

           还能够对内嵌文档创建索引,和普通键创建索引一样几乎相同。也能够对内嵌文档创建组合索引:

> db.people.ensureIndex({"friends.name" : 1})> db.people.ensureIndex({"friends.name" : 1, "friends.age" : 1})

        在来看看其它几种形式的索引:

唯一索引> db.people.ensureIndex({"name" : 1}, {"unique" : true})> db.people.ensureIndex({"name" : 1}, {"unique" : true, "dropDups" : true})松散索引> db.people.ensureIndex({"name" : 1}, {"sparse" : true})多值索引> db.people.find(){"name" : ["mary", "rose"]}> db.people.ensureIndex({"name" : 1})

        唯一索引unique能够保证该键相应的值在集合中是唯一的,假设创建唯一索引的时候,该字段原来就存在了反复的数据,那么就会创建失败,能够加上dropDups字段来消除反复数据。它会保留发现的第一个文档。其它有反复数据的文档都将被删除。

        集合中有的文档不存在某些字段。或者某些字段的值为null,那么我们在该字段上创建索引的时候不希望让这些空值的文档參与。那么就定义为松散索引sparse。比方在name上创建索引时,发现有的人在数据库中仅仅有学号。没有名字。那么我们不希望把它们也包括进来。此时就定义为松散索引。

        一个键相应的值是一个数组,在该键上创建索引时是一个多值索引。会为数组中每一个值生成一个索引元素。相当于分裂成了几个独立的索引项,可是它们还是相应同一个文档数据。

2.索引的管理

        索引固然是为查询而生,并且能够为每一个键都创建索引。可是索引是须要存储空间的,所以索引不是越多越好,并且创建索引后。每次的插入,更新和删除文档都会产生额外的开销,由于数据库中不但要运行这些操作,并且还要在集合索引中标记这些操作。所以要依据实际情况来创建索引,索引没用之后将其删除。

        创建索引是ensureIndex()方法,创建完毕后能够通过getIndexes()来查看集合中创建的索引情况:

> db.people.ensureIndex({"name" : 1, "age" : 1})> db.people.getIndexes()[        {                "v" : 1,                "key" : {                        "_id" : 1                },                "ns" : "test.people",                "name" : "_id_"        },        {                "v" : 1,                "key" : {                        "name" : 1,                        "age" : 1                },                "ns" : "test.people",                "name" : "name_1_age_1"        }]

        能够看到people集合创建了两个索引,一个是"_id",这个是默认索引。另外一个是name和age的组合索引,名字为keyname1_dir_keyname2_dir_...,keyname代表索引的键,dir代表方向。1代表升序,-1代表降序。

当然我们也能够自己定义索引的名称:

> db.people.ensureIndex({"name" : 1, "age" : 1}, {"name" : "myIndex"})> db.people.getIndexes()[        {                "v" : 1,                "key" : {                        "_id" : 1                },                "ns" : "test.people",                "name" : "_id_"        },        {                "v" : 1,                "key" : {                        "name" : 1,                        "age" : 1                },                "ns" : "test.people",                "name" : "myIndex"        }]

        删除索引是通过dropIndex():

方式一:> db.people.dropIndex({"name" : 1, "age" : 1}){ "nIndexesWas" : 2, "ok" : 1 }方式二:> db.runCommand({"dropIndexes" : "people", "index" : "myIndex"}){ "nIndexesWas" : 2, "ok" : 1 }

        索引的元信息存储在每一个数据库的system.indexes集合中。不能对其进行插入和删除文档的操作。仅仅能通过ensureIndex和dropIndex进行。

> db.system.indexes.find(){ "v" : 1, "key" : { "_id" : 1 }, "ns" : "test.people", "name" : "_id_" }{ "v" : 1, "key" : { "name" : 1, "age" : 1 }, "ns" : "test.people", "name" : "myIndex" }

        清空集合中所有的文档是不会将索引删除的,原来创建的索引依旧存在,可是直接删除集合的话,该集合的索引也是会被删除的。

3.索引的效率

        假设我们定义了非常多的索引,那么MongoDB会依据我们的查询选项又一次排序,并智能的选择一个最优的来使用。比方我们创建了{"name" : 1, "age" : 1}和{"age" : 1, "class" : 1}两个索引,可是我们的查询项为find({"age" : 10, "name" : "mary"}),那么MongoDB会自己主动又一次排序为find({"name" : "mary", "age" : 10}),并且利用索引{"name" : 1, "age" : 1}来查询。

        MongoDB提供了explain工具来帮助我们获得查询方面的非常多实用信息,仅仅要对游标调用这种方法就能够得到查询的细节。以下给math集合中加入10W个文档。再来看看使用索引前后的效率对照:

> var arr = [];> for(var i = 0; i < 100000; i++){... var doc = {};... var value = Math.floor(Math.random() * 1000);... doc["number"] = value;... arr.push(doc);... }100000> db.math.insert(arr)> db.math.count()100000> db.math.find().limit(10){ "_id" : ObjectId("53a7f7c6e4fd24348ce61fe5"), "number" : 462 }{ "_id" : ObjectId("53a7f7c6e4fd24348ce61fe6"), "number" : 123 }{ "_id" : ObjectId("53a7f7c6e4fd24348ce61fe7"), "number" : 90 }{ "_id" : ObjectId("53a7f7c6e4fd24348ce61fe8"), "number" : 46 }{ "_id" : ObjectId("53a7f7c6e4fd24348ce61fe9"), "number" : 244 }{ "_id" : ObjectId("53a7f7c6e4fd24348ce61fea"), "number" : 972 }{ "_id" : ObjectId("53a7f7c6e4fd24348ce61feb"), "number" : 925 }{ "_id" : ObjectId("53a7f7c6e4fd24348ce61fec"), "number" : 110 }{ "_id" : ObjectId("53a7f7c6e4fd24348ce61fed"), "number" : 739 }{ "_id" : ObjectId("53a7f7c6e4fd24348ce61fee"), "number" : 945 }

        通过for循环给arr数组中加入10W条数据。然后再批量插入这些数据到math集合中。查看前10条数据,由于是随即生成的值。所以number字段的值会有反复值。我们就来查询462这个值:

创建索引前:> db.math.find({"number" : 462}).explain(){        "cursor" : "BasicCursor",        "isMultiKey" : false,        "n" : 94,        "nscannedObjects" : 100000,        "nscanned" : 100000,        "nscannedObjectsAllPlans" : 100000,        "nscannedAllPlans" : 100000,        "scanAndOrder" : false,        "indexOnly" : false,        "nYields" : 0,        "nChunkSkips" : 0,        "millis" : 35,        "indexBounds" : {        },        "server" : "server0.169:9352"}创建索引后:> db.math.ensureIndex({"number" : 1})> db.math.find({"number" : 462}).explain(){        "cursor" : "BtreeCursor number_1",        "isMultiKey" : false,        "n" : 94,        "nscannedObjects" : 94,        "nscanned" : 94,        "nscannedObjectsAllPlans" : 94,        "nscannedAllPlans" : 94,        "scanAndOrder" : false,        "indexOnly" : false,        "nYields" : 0,        "nChunkSkips" : 0,        "millis" : 0,        "indexBounds" : {                "number" : [                        [                                462,                                462                        ]                ]        },        "server" : "server0.169:9352"}

        这里来看一下实用的信息,"cursor"指用的哪个索引。"nscanned"代表查找了多少个文档。"n"指返回文档的数量。"millis"表示查询所花时间。单位是毫秒。能够看出创建索引前没有使用索引。在所有的文档中查询的,花费了35毫秒。而创建索引后,使用了number_1索引查询。索引存储在B树结构中,仅仅在94个文档中查询,差点儿不花时间。

        假设有非常多索引的话,MongoDB会自己主动选一个来查询,你也能够通过hint来强制使用某个索引,这里强制使用{"age" : 1, "name" : 1}这个索引:

> db.people.find({"age" : {"$gt" : 10}, "name" : "mary"}).hint({"age" : 1, "name" : 1})

转载于:https://www.cnblogs.com/mqxnongmin/p/10969578.html

你可能感兴趣的文章
Java变量类型,实例变量 与局部变量 静态变量
查看>>
mysql操作命令梳理(4)-中文乱码问题
查看>>
Python环境搭建(安装、验证与卸载)
查看>>
一个.NET通用JSON解析/构建类的实现(c#)
查看>>
Windows Phone开发(5):室内装修 转:http://blog.csdn.net/tcjiaan/article/details/7269014
查看>>
详谈js面向对象 javascript oop,持续更新
查看>>
关于这次软件以及pda终端的培训
查看>>
jQuery上传插件Uploadify 3.2在.NET下的详细例子
查看>>
如何辨别一个程序员的水平高低?是靠发量吗?
查看>>
新手村之循环!循环!循环!
查看>>
正则表达式的用法
查看>>
线程安全问题
查看>>
SSM集成activiti6.0错误集锦(一)
查看>>
下拉刷新
查看>>
linux的子进程调用exec( )系列函数
查看>>
MSChart的研究
查看>>
C# 索引器
查看>>
MySQLdb & pymsql
查看>>
zju 2744 回文字符 hdu 1544
查看>>
delphi 内嵌汇编例子
查看>>