mongodb学习(三)-mongodb索引

3.mongodb索引

@(mongodb)

在数据量特别大(几百万)的情况下,如果没有建立索引,那么对于没有建立索引的字段进行查询将不会返回任何数据,因此建立索引是十分重要的

格式

db.COLLECTION_NAME.ensureIndex({KEY:1},{Parameter:value})
Parameter Type Description
background Boolean 建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加 “background” 可选参数。 “background” 默认值为false。
unique Boolean 建立的索引是否唯一。指定为true创建唯一索引。默认值为false.
name string 索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。
dropDups Boolean 在建立唯一索引时是否删除重复记录,指定 true 创建唯一索引。默认值为 false.
sparse Boolean 对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档.。默认值为 false.
expireAfterSeconds integer 指定一个以秒为单位的数值,完成 TTL设定,设定集合的生存时间。
v index version 索引的版本号。默认的索引版本取决于mongod创建索引时运行的版本。
weights document 索引权重值,数值在 1 到 99,999 之间,表示该索引相对于其他索引字段的得分权重。
default_language string 对于文本索引,该参数决定了停用词及词干和词器的规则的列表。 默认为英语
language_override string 对于文本索引,该参数指定了包含在文档中的字段名,语言覆盖默认的language,默认值为 language.

例子:db.values.ensureIndex({open: 1, close: 1}, {background: true})在后台创建索引
db.collenction.ensureIndex({x:1,y:2,z:3},{name="normal_index"})//指定名字
db.collenction.dropIndex("normal_index") 可用名字代替删除索引
db.collenction.ensureIndex(({m:1,n:1}, {unique: true/false})唯一索引,这里注意,如果是已经有了记录的表,可能会报错“E11000 duplicate key error collection: test.collenctionindex: m_1_n_1 dup key: { : null, : null }”原因是在你建立m:1,n:1的复合索引时,之前存在的多笔数据都没有m和n的字段,也就代表每一笔没有m和n字段的数据都是索引m:null,n:null的情形,而此时你又指定该复合索引为unique,立刻报索引重复错误!
db.collenction.ensureIndex({title : 1}, {sparse : true})稀疏索引,mongo的默认模式是密集索引,在稀疏索引的情况下,如果某个对象没有索引的属性,将不会建立一个{title:null}的索引,可加快插入的速度。和unique结合可以达成唯一插入,有则建索引,无则不建索引的效果,就不会出现上面提到的unique索引报错的情况

基本操作

db.test_collection.getIndexes() //查看集合的索引情况
db.test_collection.ensureIndex({x:1}) //创建索引,key代表字段名,value值代表方向,1代表正向排序,-1 代表负向排序

如果数据量非常大,创建索引需要消耗一定的时间,创建索引的时候需要注意时机,如果已经有大量数据了,这个时候创建索引会严重影响数据库的性能,
应该在创建数据表的时候就创建索引,索引是在插入数据之后创建的,所以,对插入数据有稍微的影响,不过对于提高的查询效率而言是值得的

索引分类

_id索引

  • _id索引是绝大多数集合默认建立的 索引。
  • 对于每个插入的数据,MongoDB都会自动生成一条唯一的_id字段。

单键索引

单键索引是最普通的索引,单键索引不会自动创建
db.test_collection.ensureIndex({x:1}) //创建单键索引

多键索引

当为一个字段插入的数据是一个数组(集合等表示多条数据就行)时,MongoDB为对应的值,默认创建了一个多键索引
db.test_collections.insert({x:[1,2,3,4]})插入一个数组

> db.test_collections.find({x:4})
{ "_id" : ObjectId("5a44f99ca3fe201251392183"), "x" : [ 1, 2, 3, 4 ] }

直接就可以通过数组中的值查出来了

复合索引

db.collection.ensureIndex({x:1,y:2})

过期索引

又称 TTL(Time To Live,生存时间)索引,即在一段时间后会过期的索引(如登录信息、日志等)
过期后的索引会连同文档一起删除

  • 存储在过期索引字段的值必须是指定的时间类型
    • 说明:必须是ISOData或者ISOData数组,不能使用时间戳
  • 如果指定的是ISOData数组,则按照数组中最小的数值计算删除
  • 过期期索引不能是复合索引,只能是单键索引
  • 删除时间不是精确
    • 说明:删除过程是由后台程序每60s跑一次,而且删除也需要一些时间
db.local_2.ensureIndex({time:1},{expireAfterSeconds:30})
db.local_2.insert({time:new Date()})
db.local_2.find()

全文索引

全文索引建立

在MongoDB中每个数据集合只能创建一个全文索引, 所以使用全文索引进行查询时不会起冲突

db.articles.ensureIndex({key:"text"})//单值索引的value是 1或者 -1代表正向或者你向,而全文索引的value则是固定的字符串”text”
db.articles.ensureIndex({key1:"text",key2:"text",key3:"text"})//多字段
db.articles.ensureIndex({"$**":"text"}) //为表的所有字段创建全文索引

使用全文索引

db.articles.find({$text:{$search:"coffee"}})
db.articles.find({$text:{$search:"aa bb cc"}}) 包含aa或bb或cc的数据
db.articles.find({$text:{$search:"aa bb -cc"}}) 包含aa或者bb,但是不包含cc的数据
db.articles.find({$text:{$search:"\"aa\" \"bb\" \"cc\""}})同时包含aa、bb、cc的数据(用“”包裹起来,引号需要用反斜杠转义)

全文索引的相似度

$meta操作符:{score:{$meta:"textScore"}}
写在查询条件之后可以返回返回结果的相似度,textScore为固定字符串
与 sort 一起使用可以达到很好的使用效果

db.imooc_2.find({$text:{$search:"aa bb"}},{score:{$meta:"textScore"}})
db.imooc_2.find({$text:{$search:"aa bb"}},{score:{$meta:"textScore"}}).sort({score:{$meta:"textScore"}});根据score字段排序

实际查询之后会见到如下所示的效果

> db.test_collection.find({$text:{$search:"aa"}},{score:{$meta:"textScore"}}).sort({score:{$meta:"textScore"}})

{ "_id" : ObjectId("5a45f28022d4795f1452d9bf"), "article" : "aa", "score" : 1.1 }
{ "_id" : ObjectId("5a45f11522d4795f1452d9bb"), "article" : "aa bb cc dd", "score" : 0.625 }
{ "_id" : ObjectId("5a45f1a222d4795f1452d9bd"), "article" : "aa bb ii gg", "score" : 0.625 }
{ "_id" : ObjectId("5a45f1b422d4795f1452d9be"), "article" : "aa bb zz yy", "score" : 0.625 }
{ "_id" : ObjectId("5a45f19b22d4795f1452d9bc"), "article" : "aa bb cc ff hh", "score" : 0.6 }

全文索引的限制:

  • 每次查询,只能指定一个$text查询
  • $text查询不能出现在$nor查询中
  • 查询中如果包含了$text, hint不再起作用
  • MongoDB全文索引在3.2版本之前还不支持中文

地理位置索引

概念:将一些点的位置存储在MongoDB中,创建索引后,可以按照位置来查找其他点
子分类:
- 2d索引:用于存储和查找平面上的点db.集合名.ensureIndex({w:"2d"})
- 2dsphere索引:用于存储和查找球面上的点db.集合名.ensureIndex({w:"2dsphere"})

位置表示方式:经纬度[精度,纬度]
取值范围:精度[-180,180],纬度[-90,90]。如果超出范围会出现意想不到的错误
查找方法:
- 查找据李某个点一定距离内的点
- 查找包含在某区域内的点

2d索引

2d索引:db.集合名.ensureIndex({w:"2d"})

例子: db.集合名.find({w:{$near:[1,1]}})
db.collection.find({w:{$near:[1,1], $maxDistance:10}})查找距离[1,1]最大距离为10的点,3.2版本后可以使用minDistance
db.collection.find({w:{$geoWithin:{$box:[[0,0],[3,3]]}}}) 查找在矩形[0,0] [3,3]范围内的点
db.collection.find({w:{$geoWithin:{$center:[[0,0],5]}}}) 查找以[0,0]为圆心半径为5的圆内的点
db.collection.find({w:{$geoWithin:{$polygon:[[0,0],[1,1],[4,5],[6,6]]}}}) 查找以[0,0],[1,1],[4,5],[6,6]为多边形内的点

想不明白的在脑子里假想一个坐标系,就很好理解了

geoNear查询:

除了使用 find的方式之外,还可以使用runCommand来执行语句

db.runCommand({
geoNear:"集合名",
near:[x, y],
minDistance: (对2d索引无效)
maxDistance:
num:(返回的数量)
{
    "results":[     //查询的结果
        {
        "dis":  //查找到的数据与所指定查找的数据之间的距离
        "obj":{}    //查找到的数据
        }
    ],
    "stats":{   //查询的参数
        "nscanned": //扫描了哪些数据
        "objectsloaded":
        "avgDistance":      //平均距离
        "maxDistance":  //最大的距离
        "time":     //花费的时间
    },
    "ok":
}

2dsphere索引

2dsphere索引: db.集合名.ensureIndex({w:"2dsphere"})

2Dsphere位置表示方式:
GeoJSON:描述一个点,一条直线,多边形等形状。
格式:
{type:”, coordinates:[list]}
GeoJSON查询可支持多边形交叉点等,支持MaxDistance 和 MinDistance

详细请看
基于MongoDB 2dSphere索引查找最近的点

索引分析

创建索引的好处:加快索引查询。
创建索引的坏处:增加磁盘消耗,降低写入性能。

索引分析的工具
- mongostat工具
- profile集合介绍
- 日志
- explain分析

mongostat

mongostat是mongodb自带的用来查看mongodb运行状态的一个工具

使用方法:./mongostat -h ip:port -u -p

字段说明:

返回的采样数据采用百分比

索引情况:idx miss 索引未命中率

输出字段:

inserts –当前的插入数量(单位:秒)
query –当前的查询数量(单位:秒)
update –当前更新的数量(单位:秒)
delete –当前的删除数量(单位:秒)
getmore –当前的迭代返回数量(单位:秒)
command –执行命令的数量
flushes –刷盘时间(单位:秒)
mapped –mmap 大小
vsize –磁盘空间大小
res –常驻内存大小
faults –内存换页时间(单位:秒)
locked –锁的使用情况
idx miss –未命中索引率
qr|qw –读|写队列
ar|aw –活跃的客户端连接数量
netIn –网卡输入流量
netOup –网卡输出流量
conn –当前连接到mongodb的连接数量

inserts/query/update/delete: 分别指当前mongodb插入、查询、更新、删除 数量,以每秒计;
getmore: MongoDB返回结果时,每次只会返回一定量;当我们继续用find()查询更多数据时,系统就会自动用getmore来获取之后的数据;
command: 执行的命令数量;
flushes: MongoDB使用虚拟内存映射的方式管理数据,我们在向MongoDB写入或查询数据时,MongoDB会做一次虚拟内存映射,有些数据其实是在硬盘上的;每隔一段时间,MongoDB会把我们写到内存的数据flush到硬盘上;这个数据大的话,会导致mongodb的性能较差;
mapped/vsize/res: 与磁盘空间大小有关,申请的内存大小;
faults:如果我们查询的数据,没有提前被MongoDB加载到内存中,我们就必须到硬盘上读取,叫做“换页”;如果faults比较高,也会造成性能下降;
idx miss: 表示我们的查询没有命中索引的比率;如果很高,说明索引构建有问题,索引不合适或者索引数量不够;
qr|qw: 说明MongoDB的写队列或者读队列的情况。我们向MongoDB读写时,这些请求会被放到队列中等待。数量大(几百上千)说明MongoDB处理速度慢或者读写请求太多,性能会下降。
ar|aw: 当前活跃的读写客户端的个数。

qr/qw 表示读队列和写队列值,较高时数据库的性能会很明显的下降
idx miss 表示查询时索引命中情况,较高时影响查询效率

profile

db.getProfilingStatus()
{ “was” : 0, “slowms” : 100 }
查看当前数据库的记录级别

db.getProfilingLevel()
0|1|2
设置当前数据库的profile记录级别
db.setProfilingLevel(0|1|2)

was –profile记录级别,0关闭,1记录所有超过slowms阈值的慢查询,2记录所有操作
slowms –慢查询阀值

查看profile文件
db.system.profile.find()
db.system.profile.find().sort({$natural:-1}).limit(1)查询profile集合的内容,自然排序,限制只显示一条日志

{ "op" : "query",--操作类型
"ns" : "imooc.system.profile", --查询的命名空间,;databasename.collectionname'
"query" : { "query" : { }, --查询条件
"orderby" : { "$natural" : -1 } }, --约束条件
"ntoreturn" : 1, --返回数据条目
"ntoskip" : 0, --跳过的条目
"nscanned" : 1, --扫描的数目含索引
"nscannedObjects" : 1, --扫描的数据数目
"keyUpdates" : 0, --
"numYield" : 0, --其他情况
"lockStats" : { --锁状态
"timeLockedMicros" : { --锁占用时间(毫秒)
"r" : NumberLong(82), --读锁
"w" : NumberLong(0) --写锁
},
"timeAcquiringMicros" : {
"r" : NumberLong(2), "w" : NumberLong(2)
}
},
"nreturned" : 1,
"responseLength" : 651, --返回长度
"millis" : 0, --查询时间

注意:如果开启了profile的功能,并且此时profile记录的数据比较大,系统的消耗是比较大的,所以,这个工具最好在上线之前的测试时开启此功能,用来查看数据库的设计和应用程序的设计,上线的系统是不建议使用此方法的,因为系统的开销比较大!

mongodb日志

就是log目录下的那个日志

berbose = vvvvv 日志记录级别,1-5个v,越多越详细

explain

db.colltction.find({x:1}).explain()

{
“cursor” : “BasicCursor”, –使用的游标
“isMultiKey” : false,
“n” : 1,
“nscannedObjects” : 100000, –扫描的数据量
“nscanned” : 100000, –包含索引的扫描量
“nscannedObjectsAllPlans” : 100000,
“nscannedAllPlans” : 100000,
“scanAndOrder” : false,
“indexOnly” : false,
“nYields” : 781,
“nChunkSkips” : 0,
“millis” : 25, –查询消耗时间(毫秒)
“server” : “XXX”,
“filterSet” : false
}

猜你喜欢

转载自blog.csdn.net/Chirskuro/article/details/78941906