难度水平:初中级
适用人群:对Mongodb数据查询已经一定经验的码农,了解explain()的用法。
阅读时间:10分钟
缘起
本来是打算回答一个网友的问题,不过回复框太小而且功能不全(差评^o^),于是乎就成就了本文的产生。在这里我主要就是想跟大家分享一下我对Mongodb索引的粗浅理解,抛砖引玉,希望能对一些人有所帮助。
对于数据库的索引相信大家都不陌生,主要功能就是在数据库内提高针对特定信息的访问速度。那么在Mongodb里面索引是怎样被引用跟查找的呢?下面我来通过几个例子给大家分享一下我的心得体会。
Mongodb基础数据查询
举个栗子,按照城市查询车牌号码系统。为了方便演示,我在所有查询后面都加入了explain()函数。要注意explain的返回结果集中的一下选项:
-
cursor
- 索引项 -
n
- 查询结果的条目总数 -
nscanned
- 扫描并读取的索引条目数(index) -
nscannedObjects
- 扫描并读取的全文条目数(documents) -
indexOnly
- 是否使用了covered indexes功能,宝宝不哭,后面有详述。 -
millis
- 查询用时,单位是毫秒。
栗子1: 在没有索引的情况下查询全部北京车牌号码
db.carLicence.find({city:'Beijing'}).explain()
//返回结果如下:
{
"cursor" : "BasicCursor",
"n" : 1563247,
"nscannedObjects" : 96539732,
"nscanned" : 96539732,
"indexOnly" : false,
"millis" : 156, // 哭!
}
BasicCursor表示全文检索。上面的例子说明,在没有索引的情况下,该查询语句查询了整个数据集carLicence。该数据集包含了96539732数据,其中1563247属于北京车牌。整个用时为156毫秒.
小结: 一定要避免没有索引的全文查询
栗子2: 在没有索引的情况下,使用limit(1000)来查询北京车牌号码
db.carLicence.find({city:'Beijing'}).limit(1000).explain()
//返回结果如下:
{
"cursor" : "BasicCursor",
"n" : 1000,
"nscannedObjects" : 18476396,
"nscanned" : 18476396,
"indexOnly" : false,
"millis" : 85, // 擦干眼泪!
}
这个例子说明,Mongodb在搜索满1000个条目之后就停止继续检索了。
小结: 尽量使用limit()来处理你的数据查询
。
栗子3: 添加索引
因为我们只是需要得到北京市的车牌号码,所以在我们的例子中涉及到了2个索引信息,一个是城市city,另外一个就是车牌号码licence。那么我们来给这2个信息添加索引,来查询全部北京车牌号码。
注意:给2个以上的字段建立索引叫做Compound Index复合索引[多字段索引),hashed字段不能创建索引。建立方法如下db.carLicence.ensureIndex( { "city": 1, "licence": 1 } )
db.carLicence.find({city:'Beijing'}).explain()
//返回结果如下:
{
"cursor" : "BasicCursor city_1_licence_1",
"n" : 1563247,
"nscannedObjects" : 1563247,
"nscanned" : 1563247,
"indexOnly" : false,
"millis" : 47, // 只剩 擦!
}
相信看到这里,大家已经对所有的功效有了一个初步的认识了。
小结 - 尽量给涉及到的条目建立索引
。
那么,indexOnly的covered indexes功能会有什么样的提高呢?好让我们来看最后这个例子。
栗子4: 使用覆盖索引 Covered Indexes
db.carLicence.find({city:'Beijing'}, {licence:1, _id:0}).explain()
//返回结果如下:
{
"cursor" : "BasicCursor city_1_licence_1",
"n" : 1563247,
"nscannedObjects" : 0,
"nscanned" : 1563247,
"indexOnly" : true, // 变了 变了 !
"millis" : 41, // 擦!擦!擦!
}
最后这个例子涉及到了covered indexes(覆盖索引),通常来说,覆盖索引只在查询文档的索引字段时候使用。但是有几个特性跟附加条件要遵循.
- 查询字段必须是索引字段
- 要去掉_id因为是返回的Object. 通过_id:0来实现。
- 索引字段不能是. 也就是说在explain()里面,如果isMultiKey:true的话indexOnly一定是false.
另外一个就是在最后一个栗子里面nscannedObjects是零,这是因为我们只是提取了索引里面的目录条licence,并不需要每一条的全部数据(document),加上"indexOnly" : true,所以, Mongodb直接从索引里面提取了数据licence,不用再去查询物理数据集carLicence得到相关全文信息。所以nscannedObjects为零。
小结 - 在只提单字段数据的前提下,要给对应的但字段建立索引索引
。
结语
粗浅的分析一下我对索引的理解跟一些优化体验。有兴趣的朋友可以共通研究。最后说一句,善用explain()能对你的优化查询有很大的益处。加油!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。