本系列文章学习来源是技术胖的MogoDB系列
索引的性能提高必须要有大量数据才能看出来,像我们之前操作数据库,用10条数据,是看不出来效果的,接下来通过随机数的方法,创造出一个百万级数据的数据库出来。
制作随机数:
我们要想生成一个百万级的数据集合,必须要有随机数的参与,我们需要写一个随机数的方法。
//生成随机数
function GetRandomNum(min,max){
let range = max-min; //得到随机数区间
let rand = Math.random(); //得到随机值
return (min + Math.round(rand *range)); //最小值+随机数取整
}
console.log(GetRandomNum(10000,99999));
制作随机用户名:
有了随机数的方法,我们就可以制作一个随机生成的用户名。目的是存在不同的用户名,方便我们测试查询速度。
//生成随机数
function GetRandomNum(min,max){
let range = max-min; //得到随机数区间
let rand = Math.random(); //得到随机值
return (min + Math.round(rand *range)); //最小值+随机数取整
}
// console.log(GetRandomNum(10000,99999));
//生成随机用户名
function GetRadomUserName(min,max){
let tempStringArray= "123456789qwertyuiopasdfghjklzxcvbnm".split("");//构造生成时的字母库数组
let outPuttext = ""; //最后输出的变量
//进行循环,随机生产用户名的长度,这里需要生成随机数方法的配合
for(let i=1 ;i
插入200万数据:
有了生成随机数和随机用户名的方法,就可以生产百万级数据了。
var db = connect('user');
db.randomInfo.drop();
var tempInfo = [];
for (let i=0;i<2000000;i++){
tempInfo.push({
username:GetRadomUserName(7,16),
regeditTime:new Date(),
randNum0:GetRandomNum(100000,999999),
randNum1:GetRandomNum(100000,999999),
randNum2:GetRandomNum(100000,999999),
randNum3:GetRandomNum(100000,999999),
randNum4:GetRandomNum(100000,999999),
randNum5:GetRandomNum(100000,999999),
randNum6:GetRandomNum(100000,999999),
randNum7:GetRandomNum(100000,999999),
randNum8:GetRandomNum(100000,999999),
randNum8:GetRandomNum(100000,999999),
})
}
db.randomInfo.insert(tempInfo);
这个过程会持续几分钟,插入完成后,我们可以使用 db.randomInfo.count()
这个命令查看数据中的数据条数。查询后发现集合中已经有了200万条数据,可以进行索引的操作了,我们先来建立一个索引,然后看看它的查询性能到底提升了多少倍。
【普通查询】
我们先制作一个普通查询,随便查找一个用户名,并计算出查询和打印的时间,因为有200万条数据,所以性能不会很高。
var startTime = new Date().getTime() //得到程序运行的开始时间
var db = connect('user') //链接数据库
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') //打印出运行时间
[SUCCESS]This run time is:1153ms
【索引查询】
为用户名(username)建立索引
db.randomInfo.ensureIndex({username:1})
查看现有索引
db.randomInfo.getIndexes()
建立一下索引大概会花费30s时间,查看结果
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "user.randomInfo"
},
{
"v" : 2,
"key" : {
"username" : 1
},
"name" : "username_1",
"ns" : "user.randomInfo"
}
]
再次执行上面的查询,[SUCCESS]This run time is:8ms,这时候查询的时间缩短到了8ms左右,查询性能提升了大概150倍左右。
无论是在关系型数据库还是文档数据库,建立索引都是非常重要的。同时,建立索引是要消耗硬盘和内存资源的,所以还是要根据程序需要进行建立了。MongoDB也给我们进行了限制,只允许我们建立64个索引值。
索引虽然很好用,但并不是所有情况都适合用索引的。
- 数据不超万条时,不需要使用索引。性能的提升并不明显,而大大增加了内存和硬盘的消耗。
- 查询数据超过表数据量30%时,不要使用索引字段查询。实际证明会比不使用索引更慢,因为它大量检索了索引表和我们原表。
- 数字索引,要比字符串索引快的多,在百万级甚至千万级数据量面前,使用数字索引是个明智的选择。
- 把你经常查询的数据做成一个内嵌数据(对象型的数据),然后集体进行索引。
复合索引
复合索引是两条以上的索引,前面我们已经把username字段建立了索引,现在把randNum0,这个字段也设置成索引。
db.randomInfo.ensureIndex({randNum0:1})
建立好后,我们再用查询索引状态命令进行查询。
db.randomInfo.getIndexes()
这时候已经是两个自建索引了,一共有三个索引。
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "user.randomInfo"
},
{
"v" : 2,
"key" : {
"randNum0" : 1
},
"name" : "randNum0_1",
"ns" : "user.randomInfo"
},
{
"v" : 2,
"key" : {
"username" : 1
},
"name" : "username_1",
"ns" : "user.randomInfo"
}
]
【两个索引同时查询】
同时查询两个索引的值,看看性能如何。
var startTime=new Date().getTime();
var db = connect('user');
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');
[Demo]this run time is 8ms,从性能上看并没有什么特殊的变化,查询时间还是在8ms左右。这是因为MongoDB的复合查询是按照索引顺序进行查询的,就是我们用db.randomInfo.getIndexes()
查询出的数组。
【指定索引查询(hint)】
数字的索引要比字符串的索引快,这就需要一个方法来打破索引表的查询顺序,用我们自己指定的索引优先查询,这个方法就是hint().
var rs= db.randomInfo.find({username:'7xwb8y3',randNum0:565509}).hint({randNum0:1});
[Demo]this run time is 3ms,查询速度的确加快了。
【删除索引】
当索引性能不佳或起不到作用时,我们需要删除索引,删除索引的命令是dropIndex()。
db.randomInfo.dropIndex('randNum0_1');//索引的唯一ID
这里需要注意的是删除时填写的值,并不是我们的字段名称(key),而是我们索引查询表中的name值,也支持删除全部的索引。
db.randomInfo.dropIndexes()
全文索引
有时候需要在大篇幅的文章中搜索关键词,MongoDB为我们提供了全文索引。
我们先建立一个集合(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这个单词的记录,我们可以使用“-”减号来取消。
db .info.find({$text:{$search:"programmer family diary -drink"}})
转义符
全文搜索中是支持转义符的,比如我们想搜索的是两个词(love PlayGame和drink),这时候需要使用\斜杠来转意。
db.info.find({$text:{$search:"\"love PlayGame\" drink"}})