集合中已经有了200万条的数据,可以进行索引的操作了。我们先来建立一个索引,然后看看它的查询性能到底提升了多少倍。这个不会很难,主要掌握索引的建立方法即可。
普通查询性能
我们先制作一个普通查询,随便查找一个用户名,并计算出查询和打印的时间,因为有200万条数据,所以性能不会很高。
var startTime = new Date().getTime() //得到程序运行的开始时间
var db = connect('company') //链接数据库
var rs=db.randomInfo.find({username:"tfruhjy8k"}) //根据用户名查找用户
rs.forEach(rs=>{printjson(rs)}) //循环输出
var runTime = new Date().getTime()-startTime; //得到程序运行时间
print('[SUCCESS]This run time is:'+runTime+'ms') //打印出运行时间
上边的代码就是一个普通的查询,只不过是记录了时间。在终端运行后,可以得到大概的运行时间是0.8秒左右(电脑性能不同,有所不同),第一次无缓存的运行时间大概是3.5秒左右。这个时间是没办法满足我们的日常查询的。
建立索引
试着为用户名(username)建立索引。建立索引只需要一句话就可以了。
db.randomInfo.ensureIndex({username:1})
查看现有索引
db.randomInfo.getIndexes()
终端的结果,现在只有一个索引值:
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "company.randomInfo"
}
]
那现在使用命令建立一下索引db.randomInfo.ensureIndex({uername:1}),我的电脑大概要50秒左右,建立好后我们重新使用db.randomInfo.getIndexes(),查看一下结果。
结果如下:已经变成了两条索引。
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "company.randomInfo"
},
{
"v" : 2,
"key" : {
"username" : 1
},
"name" : "uername_1",
"ns" : "company.randomInfo"
}
]
然后我们在来load一下demo07.js文件(load(‘./demo07.js’)),看一下现在多少秒可以查询出来。这时候查询的时间缩短到了4ms左右,查询性能提升了大概200倍左右。
总结:无论是在关系型数据库还是文档数据库,建立索引都是非常重要的。前边讲了,索引这东西是要消耗硬盘和内存资源的,所以还是要根据程序需要进行建立了。MongoDB也给我们进行了限制,只允许我们建立64个索引值。
复合索引
索引中的小坑
记得我刚学MongoDB时,学会了索引,我就到处想用,甚至几百条数据的集合(collections),我也自作聪明的用一下,但结果往往是画蛇添足,走了不少弯路。通过实际开发和性能对比,我自己总结了几条不用索引的情况(不一定对,但是自己的经验之谈)。
- 数据不超万条时,不需要使用索引。性能的提升并不明显,而大大增加了内存和硬盘的消耗。
- 查询数据超过表数据量30%时,不要使用索引字段查询。实际证明会比不使用索引更慢,因为它大量检索了索引表和我们原表。
- 数字索引,要比字符串索引快的多,在百万级甚至千万级数据量面前,使用数字索引是个明确的选择。
- 把你经常查询的数据做成一个内嵌数据(对象型的数据),然后集体进行索引。
复合索引
好了上边我们讲了一大堆理论,现在来看复合索引。复合索引就是两条以上的索引。上节课我们已经把username字段建立了索引,我们现在把randNum0,这个字段也设置成索引。
db.randomInfo.ensureIndex({randNum0:1})
建立好后,我们再用查询索引状态命令进行查询。
db.randomInfo.getIndexes()
这时候已经是两个自建索引了,一共有三个索引。
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "company.randomInfo"
},
{
"v" : 2,
"key" : {
"username" : 1
},
"name" : "username_1",
"ns" : "company.randomInfo"
},
{
"v" : 2,
"key" : {
"randNum0" : 1
},
"name" : "randNum0_1",
"ns" : "company.randomInfo"
}
]
两个索引同时查询
我们同时查询两个索引的值,看看效果是怎么样的。
var startTime=new Date().getTime();
var db = connect('company');
var rs= db.randomInfo.find({username:'7xwb8y3',randNum0:565509});
rs.forEach(rs=>{printjson(rs)});
var runTime = new Date().getTime()-startTime;
print('[Demo]this run time is '+runTime+'ms');
从性能上看并没有什么特殊的变化,查询时间还是在4ms左右。MongoDB的复合查询是按照我们的索引顺序进行查询的。就是我们用db.randomInfo.getIndexes()查询出的数组。
指定索引查询(hint)
数字的索引要比字符串的索引快,这就需要一个方法来打破索引表的查询顺序,用我们自己指定的索引优先查询,这个方法就是hint().
var rs= db.randomInfo.find({username:'7xwb8y3',randNum0:565509}).hint({randNum0:1});
删除索引
当索引性能不佳或起不到作用时,我们需要删除索引,删除索引的命令是dropIndex().
db.randomInfo.dropIndex('randNum0_1');//索引的唯一ID
这里需要注意的是删除时填写的值,并不是我们的字段名称(key),而是我们索引查询表中的name值。这是一个小坑,希望小伙伴们不要踩中。
全文索引
准备工作:
这节我们先建立一个集合(collections)-info,然后插入一小段文章,作用就是为建立全文索引提供数据,当然我们不再建立百万级数据,我们只是看一下效果。
db.info.insert({contextInfo:"I am a programmer, I love life, love family. Every day after work, I write a diary."})
db.info.insert({contextInfo:"I am a programmer, I love PlayGame, love drink. Every day after work, I playGame and drink."}
当然这很简单,再次强调这只是文章需要,实际工作中这么简单的数据没必要建立全文索引。
建立全文索引
db.info.ensureIndex({contextInfo:'text'})
需要注意的是这里使用text关键词来代表全文索引,我们在这里就不建立数据模型了。
全文索引查找 建立好了全文索引就可以查找了,查找时需要两个关键修饰符:
- $text:表示要在全文索引中查东西。
- $search:后边跟查找的内容。
db.info.find({$text:{$search:"programmer"}})
查找多个词
全文索引是支持多个次查找的,比如我们希望查找数据中有programmer,family,diary,drink的数据(这是或的关系),所以两条数据都会出现。
db.info.find({$text:{$search:"programmer family diary drink"}})
如果我们这时候希望不查找出来有drink这个单词的记录,我们可以使用“-”减号来取消。
dbd .info.find({$text:{$search:"programmer family diary -drink"}})
转义符:
全文搜索中是支持转义符的,比如我们想搜索的是两个词(love PlayGame和drink),这时候需要使用\斜杠来转意。
db.info.find({$text:{$search:"\"love PlayGame\" drink"}})
全文索引在工作还是经常使用的,比如博客文章的搜索,长文件的关键词搜索,这些都需要使用全文索引来进行。