【赵强老师】MongoDB中的索引(上)
索引是提高查询查询效率最有效的手段。索引是一种特殊的数据结构,索引以易于遍历的形式存储了数据的部分内容(如:一个特定的字段或一组字段值),索引会按一定规则对存储值进行排序,而且索引的存储位置在内存中,所在从索引中检索数据会非常快。如果没有索引,MongoDB必须扫描集合中的每一个文档,这种扫描的效率非常低,尤其是在数据量较大时。
一、索引的基础知识
下面以关系型数据库Oracle为例,介绍索引的基本原理,如下图所示:
从上图可以看成,索引的本质其实就相当于是一本书的目录。当查询表中数据的时候,先查询目录(索引)中的行地址,再通过行地址查询到表中的数据,从而提高查询的性能。
下图说明了在MongoDB中,索引在查询和排序中是如何工作的?
通过这个例子,可以清楚的看到索引存储的是一个特定字段或者几个字段的集合,并且按照一定的规律排序。当创建集合的时候,MongoDB自动在_id上创建一个唯一性索引,由于是唯一性的,所以可以防止重复的_id值插入到集合中。通过getIndexes可以查询到MongoDB集合上的索引信息,如下图所示。
当没有索引的时候,通过查看执行计划,可以看到查询的过程,如下:查询:10号部门,工资小于3000的文档。
那么如何创建一个简单的索引呢?注意从mongoDB 3.0开始ensureIndex被废弃,今后都仅仅是db.collection.createIndex的一个别名。
现在在deptno和sal上建立一个索引,并重新查看执行计划:db.emp.createIndex({"deptno":1,"sal":-1})
注意:除了可以使用explain()生成执行计划外,还可以有几个可选的参数,如下:
.explain("allPlansExecution")
.explain("executionStats")
.explain("queryPlanner")
二、索引的类型一:单键索引(Single Field)
单键索引是最普通的索引,与_id索引不同,单键索引不会自动创建。
准备数据:
db.testindex1.insert({"_id":1,"zipcode":1034,"location":{state:"NY",city:"New York"}})
在单个列上创建单键索引:
db.testindex1.createIndex({"zipcode":1})
在嵌套的列上创建单键索引
db.testindex1.createIndex({"location:state":1})
在内嵌的文档上创建单键索引
db.testindex1.createIndex({"location":-1})
这样将会把location作为一个整体。
三、索引的类型二:多键索引(Multikey Index)
多键索引与单键索引创建形式相同,区别在于字段的值。值具有多个记录,如数组。
如上图,基于集合上的数组创建多键索引,且数组为内嵌文档。
准备数据:
db.testindex2.insertMany([
{ _id: 5, type: "food", item: "aaa", ratings: [ 5, 8, 9 ] },
{ _id: 6, type: "food", item: "bbb", ratings: [ 5, 9 ] },
{ _id: 7, type: "food", item: "ccc", ratings: [ 9, 5, 8 ] },
{ _id: 8, type: "food", item: "ddd", ratings: [ 9, 5 ] },
{ _id: 9, type: "food", item: "eee", ratings: [ 5, 9, 5 ] }])
下面基于ratings列创建一个多键索引:
db.testindex2.createIndex( { ratings: 1 } )
查询数组上为5,9的文档
db.testindex2.find( { ratings: [ 5, 9 ] } )
下面查看其执行计划
db.testindex2.find( { ratings: [ 5, 9 ] } ).explain()