---------------------------------------------------------------------------------------------------------------
[版权申明:本文系作者原创,转载请注明出处]
文章出处:http://blog.csdn.net/sdksdk0/article/details/51765219
作者:朱培   ID:sdksdk0
---------------------------------------------------------------------------------------------------------------
本文主要内容包括nosql的简介、mongodb的简介、mongodb的体系结构、mongodb在linux和window中的安装配置、安全控制、mongodb的基本数据操作(包括创建数据库,建表,增删改查等)、索引(查询索引、全文索引,地理位置索引等7大索引方式)的使用等主要内容。要求掌握mongodb的双平台配置,基本数据操作,索引的使用,安全控制,索引分析等。

一、NoSql简介

NoSQL,泛指非关系型的数据库。随着互联网web2.0网站的兴起,传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题。

传统的结构化的数据:固定长度,固定的类型

非结构化的数据:doc,ppt,pdf.

nosql(不仅仅是数据库可以干的事情),指的是非关系型数据库,以键值对存储,它的结构不固定,没一条记录可以有不一样的键,每条记录可以根据需要增加一些自己的键值对,这样就不会局限于固定的结构,可以减少一些时间和空间的开销。

常见的有:CouchDB、Redis、MongoDB、Neo4j、HBase、BigTable

二、MongoDB简介

MongoDB 是一个基于分布式文件存储的数据库。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。
MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。

是用c++写的非关系型数据库,特点是高性能、易部署、易使用,存储数据非常方便,面向集合存储,易于存储对象类型的数据,模式自由,支持动态查询,支持完全索引,包含内部对象,支持复制和故障恢复,使用高效的二进制数据存储,包括大型对象,文件存储格式为BSON(一种json的扩展)。

三、MongoDB的体系结构

MongoDB 的逻辑结构是主要由:文档(document)、集合(collection)和数据库(database)这三部分组成的。
MongoDB 的文档(document),相当于关系数据库中的一行记录
集合(collection),相当于关系型数据库中的表的概念
文档(document)、集合(collection)、数据库(database)的层次结构如下图:

四、MongoDB安装配置

4.1 linux中安装

这里服务器用ubuntu15.10,在secureCRT中连接这个ubuntu。 首先使用 rz 上传window中从官网(https://www.mongodb.com/)下载的mongodb安装文件。

解压这个文件:

tar -xvzf  mongodb-linux-x86_64-ubuntu1404-3.2.7.tgz

//重命名

 mv mongodb-linux-x86_64-ubuntu1404-3.2.7  mongodb3.2

在目录中新建data,log和conf文件夹,在cong中新建mongodb.config,内容如下:

port=27017
dbpath=data
logpath=log/mongod.log
fork=true

启动服务:

./bin/mongod -f conf/mongodb.config

连接: mongo客户端连接

bin/mongo 192.168.44.131:27017/test


在linux中连接成功:

MongoDB实用教程-LMLPHP

网页端:可以在浏览器中查看一下:http://www.192.168.44.131:27017/

MongoDB实用教程-LMLPHP

关闭:

db.shutdownServer();

查看端口号: ps -ef|grep mongod|grep 27017

kill 相应端口

4.2 window中安装

安装过程与linux基本相同,就是配置一下环境变量,创建data,log,conf目录等。

如果是在window中,启动成功会是这样:

MongoDB实用教程-LMLPHP

浏览器中访问:http://www.localhost:28017/

在mongodb有的版本中会提示端口号加1000的,所以我终于演示的时候是28017端口。

MongoDB实用教程-LMLPHP

五、MongoDB安全控制

创建用户

安全性从高到低: 物理隔离、网络隔离、防火墙隔离、用户名密码。

开启权限认证: 在配置文件中——mongodb.config中设置:

auth=true

创建用户:(2.6之前是addUser)

createUser{user:"", pwd:"cleartext password", customData:{}, roles:[{role:"", db:""}] }

例如:创建用户名为zp,密码为a的用户

db.createUser({user:"zp",pwd:"a",roles:[{role:"userAdmin",db:"admin"},{role:"read",db:"test"}]})

登陆:

bin/mongod 192.168.44.131 -u zp -p a

角色类型

数据库角色 :read, readWrite,dbAdmin, dbOwner, userAdmin

集群角色:clusterAdmin,clusterManager

备份角色:backup,restore

其他:DBAdminAnyDatabase

六、MongoDB基本数据操作

//查看数据库

show dbs

//查看表

show tables

//创建数据库

use one_db

//插入数据 格式:db.表名.insert({ json格式的数据 }) 例如:

db.one_db_collection.insert({ x:1 })

//查询刚才写入的表

show collections

查询具体内容 db.onedbcollection.find()

运行结果为:

{ "_id" : ObjectId("576fdc6e8224cdb105bcb3df"), "x" : 1 }

id是系统自动生成的,每条数据的id是唯一的 我们还可以自己给_id赋值:

db.one_db_collection.insert({x:2,_id:1})

批量插入多条数据

for(i=4;i<20;i++)db.one_db_collection.insert({x:i})

统计条数:

db.one_db_collection.find().count()

过滤排序:

db.one_db_collection.find().skip(5).limit(3).sort({x:1})

从x:1开始,过滤前5条数据,然后从第6条开始选取3条数据,并进行排序。

演示效果如下:

MongoDB实用教程-LMLPHP

//更新数据

db.one_db_collection.update({x:1},{x:100})

当插入这样的一条数据的时候:

db.one_db_collection.insert({x:100,y:100,z:100})

这个时候更新y的值,需要加$set符号:

db.one_db_collection.update({z:100},{$set:{y:200}})

当更新一条不存在的数据的时候,如果加上true则会自动创建一条这个不存在的数据

db.one_db_collection.update({y:100},{y:300},true)

效果如下:

MongoDB实用教程-LMLPHP

//一次性更新多条相同的数据

db.one_db_collection.update({ y:300},{$set:{y:301}},false,true)

如果有多条重名的且update时未加true,则只删除相同数据中的第一条数据。

MongoDB实用教程-LMLPHP

//数据的删除

db.one_db_collection.remove({y:301})

//删除表

db.one_db_collection.drop()

七、查询索引

//查看当前表中索引

db.one_db_collection.getIndexes()

//创建索引

db.one_db_collection.ensureIndex({x:1})

x:1代表正向排序,x:-1代表逆向排序。如果文档数目较大,则创建索引时间会较长。如果系统中已经有很多文档了,这个时候就不能使用这个命令去创建索引了,否则严重影响数据库性能。 我们一般需要在使用数据库之前就要把索引创建完毕。 使用索引可以明显加快查询速度。

MongoDB实用教程-LMLPHP

索引的属性 :

名字,由name指定;唯一性,unique指定;稀疏性,sparse指定

db.collection.ensureIndex({},{name:""})
db.collection.ensureIndex({},{unique:true/false})
db.collection.ensureIndex({},{sparse:true/false})

索引的类型

  • 1:_id索引
  • 2:单键索引
  • 3:多键索引
  • 4:复合索引
  • 5:过期索引
  • 6:全文索引
  • 7:地理位置索引

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

  db.one_db_collection.ensureIndex({x:1})

例如查询结果为: { "_id" : ObjectId("576fecca8224cdb105bcb3f1"), "x" : 1 }

多键索引: 1.多键索引与单键索引创建形式相同,区别在于字段的值。 1)单键索引:值为一个单一的值,如字符串,数字或日期。 2)多键索引:值具有多个记录,如数组。

 db.twodb.insert({x:[1,2,3,4,5]})

复合索引:

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

过期索引: 此索引过一段时间会过期,索引过期后,相应的数据会被删除,适合存储一些在一段时间之后会失效的数据,比如用户登录信息.

db.twodb.ensureIndex({time:1},{expireAfterSeconds:60})  //过期时间设置为60秒

db.twodb.insert({time:new Date()})

db.twodb.find() //60秒后就查不到数据了

过期索引的限制: 1.存储在过期索引字段的值必须是指定的时间类型,必须是ISODate或者ISODate数组,不能使用时间戳,否则不能自动删除。 例如 >db.twodb.insert({time:1}),这种是不能被自动删除的 2.如果指定了ISODate数组,则按照最小的时间进行删除。 3.过期索引不能是复合索引。因为不能指定两个过期时间。 4.删除时间是不精确的。删除过程是由MongoDB的后台进程每60s跑一次的,而且删除也需要一定时间,所以存在误差。

MongoDB实用教程-LMLPHP

八、全文索引

对字符串与字符串数组创建全文可搜索的索引

创建全文索引的方法

db.threedb.ensureIndex({key:"text"})
db.threedb.ensureIndex({key_1:"text",key_2:"text"})
db.threedb.ensureIndex({"$**":"text"})

演示创建一个全文索引

db.threedb.ensureIndex({"article":"text"})

插入几条演示数据

 db.threedb.insert({"article":"aa  bb cc dd ee  11"})
db.threedb.insert({"article":"aa dd rr jj ff 22"})
db.threedb.insert({"article":"aa oo qq tt kk 33"})

使用全文索引进行查询 //搜索标题中有aa的记录

 db.threedb.find({$text:{$search:"aa"}})

//多个关键字查找,查找只要含有dd qq 33中任何一个的就可以("或"关系)

db.threedb.find({$text:{$search:"dd  qq 33"}})

//查找包含dd qq但是不包含33的数据,在关键词前面加上-号代表不包含:

db.threedb.find({$text:{$search:"dd  qq -33"}})

MongoDB实用教程-LMLPHP

//"与"关系查找,既包含aa 又包含qq的数据

db.threedb.find({$text:{$search:"\"aa\" \"qq\" "}})

MongoDB实用教程-LMLPHP

//相似度查询

使用$meta:{score:{$meta:"textScore"}} 写在查询条件后面可以返回结果的相似度,与sort一起使用,可以达到很好的实用效果。

db.threedb.find({$text:{$search:"dd qq 33"}},{score:{$meta:"textScore"}})

db.threedb.find({$text:{$search:"dd  qq 33"}},{score:{$meta:"textScore"}}).sort({score:{$meta:"textScore"}})

MongoDB实用教程-LMLPHP

全文搜索的使用限制

  1. 每次查询,只能指定一个$text查询
  2. $text查询不能出现在$nor查询中
  3. 查询中如果包含了$text, hint不再起作用
  4. MongoDB全文索引还不支持中文

九、地理位置索引

将一些点的位置存储在Mongodb数据库中,并且创建索引,这些就是地理位置索引,之后就可以按照位置来查找其他的点了!

分类 1.2D索引,用于存储和查找平面上的点。 2.2Dsphere索引,用于存储和查找球面上的点。

查找方式: 1:查找距离某个点一定距离内的点 2:查找包含在某个区域内的点

2D索引

2D地理位置索引创建方式 db.collection.ensureIndex({w:"2d"}) 2D地理位置索引的取值范围以及表示方法 经纬度[经度,纬度] 经纬度取值范围 经度[-180,180] 纬度[-90,90]

//创建2d索引

db.location.ensureIndex({"w":"2d"})

//插入数据 db.location.insert({w:[20,30]}) db.location.insert({w:[160,90]}) db.location.insert({w:[20,90]}) db.location.insert({w:[80,120]})

1、使用$near 查询距离某个点最近的点 db.collection.find({w:{$near:[x,y]}}) 使用$near默认返回最近的100个点,可以使用$maxDistance:x 限制返回的最远距离 查询距离(1,1)最近的点

db.location.find({w:{$near:[1,1]}})

查询在最远距离为100的点

db.location.find({w:{$near:[1,1],$maxDistance:100}})

MongoDB实用教程-LMLPHP

2、使用$geoWithin 查询某个形状内的点 形状的表示方式: 1. $box 矩形,使用{$box:[[x1,y1],[x2,y2]]} 2. $center 圆形,使用 {$center:[[x,y],r]} 3. $polygon 多边形,使用 {$polygon:[[x1,y1],[x2,y2],[x3,y3]]}

//查询在(0,0)(80,80)之间的位置的数据 一个矩形

db.location.find({w:{$geoWithin:{$box:[[0,0],[80,80]]}}})

MongoDB实用教程-LMLPHP

//圆形区域内,原心为(20,30),半径是80

db.location.find({w:{$geoWithin:{$center:[[20,30],80]}}})

MongoDB实用教程-LMLPHP

//多边形

 db.location.find({w:{$geoWithin:{$polygon:[[0,0],[40,30],[80,100],[30,60]]}}})

MongoDB实用教程-LMLPHP

//geoNear的使用 格式: db.runCommand({geoNear:,near:[x,y],minDistance:maxDistance:num:})

查询距离(1,1)最远距离为100的,最多返回1条数据

db.runCommand({geoNear:"location",near:[1,1],maxDistance:100,num:1})

MongoDB实用教程-LMLPHP

球面地理位置索引

2dsphere索引

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

db.collection.ensureindex({key: '2dsphere'})

十、索引构建情况分析

如何评判当前索引构建情况: 1.mongostat 工具

使用mongostat -h [ip]:端口 例如:

bin/mongostat  -h  192.168.44.131:27017

MongoDB实用教程-LMLPHP

idx miss和qr|qw是需要我们重点关注的地方。

2.profile集合

db.getProfilingStatus()
db.getProfilingLevel()

当level为0代表profiling是关闭的. 级别为1时会记录所有超过slowms中设定的数目的操作。 级别为2时会记录你的所有操作。

3.日志分析

在配置文件中——mongodb.config中设置:

verbose=VVVVV

设置日志,5个v记录最详细的数据,1个v记录简单的日志信息。1到5个v来进行设置。

4.使用explain查询分析器分析

db.collection.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 }

十一、总结

1:为什么有这么多种索引?

不同的情况下使用对应情况下的索引,可以让查询速度更快,可以使查询得到进一步的优化。

2:什么时候使用什么索引才是合适的?

简单的说,索引就好比一本书的目录,你只要浏览标题就可以快速的找到具体内容是放在哪一页的。也就是说用find()查找时不用直接去搜索表,只要查找索引,就可以直接定位到你想查找的内容位置。索引带来的方便不是免费的,是以每次插入或更新(相当于删除并插入)时都要维护索引为代价的。所以如果一张表更多是用于查询而很少插入,那么就可以建立尽量多的索引以优化查询性能。相反如果一张表要经常插入或更新,则尽可能少用索引,有时甚至连主键都不建。

3:怎么判断索引建立的合适与否?

索引的建立必须慎重,对每个索引的必要性都应该经过仔细分析,要有建立的依据.因为太多的索引与不充分、不正确的索引对性能都毫无益处:在表上建立的每个索引都会增加存储开销,索引对于插入、删除、更新操作也会增加处理上的开销.另外,过多的复合索引,在有单字段索引的情况下,一般都是没有存在价值的;相反,还会降低数据增加删除时的性能,特别是对频繁更新的表来说,负面影响更大.

05-11 20:03