您的位置:首页 > 数据库 > Mongodb

mongodb学习(三)-mongodb索引

2017-12-31 15:11 351 查看

3.mongodb索引

@(mongodb)

mongodb索引
格式

基本操作

索引分类
_id索引

单键索引

多键索引

复合索引

过期索引

全文索引
全文索引建立

使用全文索引

全文索引的相似度

全文索引的限制

地理位置索引
2d索引

geoNear查询

2dsphere索引

索引分析
mongostat

profile

mongodb日志

explain

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

格式

db.COLLECTION_NAME.ensureIndex({KEY:1},{Parameter:value})


ParameterTypeDescription
backgroundBoolean建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加 “background” 可选参数。
4000
“background” 默认值为false。
uniqueBoolean建立的索引是否唯一。指定为true创建唯一索引。默认值为false.
namestring索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。
dropDupsBoolean在建立唯一索引时是否删除重复记录,指定 true 创建唯一索引。默认值为 false.
sparseBoolean对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档.。默认值为 false.
expireAfterSecondsinteger指定一个以秒为单位的数值,完成 TTL设定,设定集合的生存时间。
vindex version索引的版本号。默认的索引版本取决于mongod创建索引时运行的版本。
weightsdocument索引权重值,数值在 1 到 99,999 之间,表示该索引相对于其他索引字段的得分权重。
default_languagestring对于文本索引,该参数决定了停用词及词干和词器的规则的列表。 默认为英语
language_overridestring对于文本索引,该参数指定了包含在文档中的字段名,语言覆盖默认的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 –网卡输
a671
出流量

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

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: