MongDB属于非关系型数据库一派,没有固定的数据格式存储,是一个具备高性能、高拓展的文档型数据库,数据以BSON(JSON的二进制)的格式存储。
特点:
- 基于对象模型,关系简单。没有外键的约束,也没有强连接表的关系,适用于对需求不确定的系统开发。
- 反范式、无关联的组织结构极大的加快了查询的速度。
- 同一个集合中对象包含的字段可以不同,能根据需求快速响应,属于半结构化数据,对开发十分友好便捷。
- MongoDB支持高可用,实现一主多从,主节点宕机了,从节点会经过筛选承担主节点的位置。
- MongoDB支持可拓展,对于数据可进行分片处理,对于应用透明。
- 提供JS形式的API方法,操作简便
一、MongoDB基本概念(同关系型数据库对比)
1.专有名词
关系型数据库 | MongoDB |
---|---|
字段(field) | 字段(field) |
行(row) | 文档(document) |
表(table) | 集合(collection) |
数据库(database) | 数据库(database) |
主键(自定义 primary key) | 主键(_id,自动生成 ) |
索引(index) | 索引(index) |
表连接(left join) | 聚合操作(管道)) |
2.JSON vs BSON
JSON | BSON | |
---|---|---|
存在形式 | 基于文本形式 | 基于二进制编/解码 |
遍历速度 | 较慢 | 快 |
数据类型 | 6种 | 丰富 |
JSON支持的六种基础类型:
string: 字符串
number : 数值
object: JS的对象形式,用{key:value}表示
可嵌套 array: 数组,JS的表示方式[value]
布尔类型 true/false:
null: 空值
2.1 BSON数据格式
可以利用BSON的数据格式type进行查询匹配,例如:db.collection.find({"title" : {$type : "string"}})
部分数据类型讲解
2.1.1 时间类型
db.collection.insert([{data1:Date()},{data2:new Date()},{data3:ISODate()}])
ISODate() = new Date(),得到的是UTC的时间,Date()得到的是本地时间
2.1.2 ObjectId生成器
所有的文档都有一个_id字段,且是唯一的,相当于主键。_id字段的值采用16进制编码形式,共12个字节。是通过ObjectId生成器生成的,且具有一定的规则来保证唯一。
ObjectId被定义为3个部分: 4字节表示Unix时间戳(秒)。 5字节表示随机数(机器号+进程号唯一)。 3字节表示计数器(初始化时随机)。
二、MongoDB命令基本使用
1、用户操作
2、集合操作
3、文档操作
三、固定集合(capped collection)
固定集合,从字面意思就可以知道,长度是固定的,适用于短时间使用的数据存储。遵循先进先出的原则,所以当空间已满时,会将最先进的文档,进行取代。
db.createCollection("logs",{capped:true,size:4096,max:10})
capped: true 指定为固定集合,size指定固定集合存储空间的大小
优势:
- 遵循先进先出原则,底层根据顺序IO操作,读写性能高
缺点:
-
无法动态修改存储的上限
-
无法删除已有的数据
四、WiredTiger(读写模型存储引擎)
引入WiredTiger,对于MongoDB就是如虎添翼,加快了读写的效率,也进一步保障数据的不丢失。
读取依赖于WiredTiger的内存缓存,主要原理如下:
- 数据库发起读IO操作,操作系统将磁盘数据经过调度加载在页面缓存区中。
- 存储引擎读取页面的数据,通过加压缩的方式存储在内存缓存区中。
- 在存储引擎内存中进行匹配,匹配成功后返回结果。
写操作(减少磁盘IO,提高速率): 当数据发生写入时,MongoDB并不会立即持久化到磁盘上,而是先在内存中记录这些变更,之后通过CheckPoint机制将变化的数据写入磁盘。
主要基于两部分保障数据的不丢失
- 基于快照(CheckPoint): 每60秒一次进行保存
- 基于日志(Journal): 保存所有的写操作,以便快照失效能保存数据
另外MongoDB为了尽可能保证业务查询的"热数据"能快速被访问,其内部缓存的默认大小达到了内存的一半。
五、 mongoDB索引讲解
索引的建立是为了更快速的获取到查询的结果,MongoDB的索引数据结构选取的是B+tree。
索引的分类有如下几种情况:
- 按照索引的字段数量进行分类: 单键索引、组合索引(复合索引)
- 按照索引的字段是否为主键进行分类: 主键索引、非主键索引
- 按照索引节点中物理记录来区分,聚簇索引(包含指针和数据)、非聚簇索引(只有指针)
- 索引特性: 唯一索引、地理位置索引、ttl索引、文本索引、稀释索引等。
1.索引操作命令
索引创建操作命令的options参数有
1.1 普通索引
db.collection.createIndex(keys, options) 创建索引命令
其中key,指定1为升序,指定-1为降序
# 创建索引后台执行
db.collection.createIndex({open: 1, close: 1}, {background: true})
#创建唯一索引,在options位置上添加unique:true即可
db.collection.createIndex({_id: 1},{unique: true})
//查看当前集合的所有索引
db.collection.getIndexes()
//查看当前集合的所有索引健
db.collection.getIndexKeys()
//查看索引所占空间
db.collection.totalIndexSize([is_detail])
//删除索引
db.collection.dropIndex('索引名称')
//删除集合下所有索引
db.collection.dropIndexes();
1.2 复合索引
创建复合索引(索引包含多个字段值)
db.collection.createIndex({type:1,favCount:1})
1.3 多键索引(与复合索引不同)
例如 ratings: [1,2,3]是一个数组,包含了多个值,在此基础上建立索引称为多键索引
db.collection.createIndex({rating:1})
在范围上 多键索引<= 复合索引
1.4 地理位置索引
// 创建一个2dsphere索引
db.collection.createIndex({location : "2dsphere"})
// 查询附近10000米商家信息
db.restaurant.find( {
location:{
$near :{
$geometry :{
type : "Point" ,
coordinates : [ -73.88, 40.78 ]
} ,
$maxDistance:10000
}
}
} )
参数说明
$near
查询操作符,用于实现附近商家的检索,返回数据结果会按距离排序。$geometry
操作符用于指定一个GeoJSON格式的地理空间对象,type=Point表示地理坐标点,coordinates则是用户当前所在的经纬度位置;$maxDistance
限定了最大距离,单位是米。
1.5 全文索引
全文索引能实现简易的分词检索,选定索引字段后,赋值为text即为全文索引。
#创建全文索引
db.collection.createIndex( { comment: "text" } )
// 通过$text操作符来查寻数据中所有包含"coffee","shop","java"列表中任何词语的商店
db.colletion.find({$text: {$search: "java coffee shop"}})
1.6 Hash索引
哈希索引使用哈希来创建索引,能实现精确匹配,但不支持范围索引和多键Hash。
db.collection.createIndex({name: "hashed"})
1.7通配符索引
对于索引建立的字段不确定时,可以使用通配符进行索引,用$**的方式进行匹配。
db.collection.insert([
{
"product_name" : "Spy Coat",
"product_attributes" : {
"material" : [ "Tweed", "Wool", "Leather" ],
"size" : {
"length" : 72,
"units" : "inches"
}
}
},
{
"product_name" : "Spy Pen",
"product_attributes" : {
"colors" : [ "Blue", "Black" ],
"secret_feature" : {
"name" : "laser",
"power" : "1000",
"units" : "watts",
}
}
},
{
"product_name" : "Spy Book"
}
])
# 创建通配符索引
db.collection.createIndex( { "product_attributes.$**" : 1 } )
# 通配符索引的使用
db.collection.find( { "product_attributes.size.length" : { $gt : 60 } } )
db.collection.find( { "product_attributes.material" : "Leather" } )
db.collection.find( { "product_attributes.secret_feature.name" : "laser"
特性:
1.通配符索引不适用于其他特性的索引
2.通配符索引不能用于查询不存在字段的文档
3.通配符索引不能支持精确的对象或数据精准匹配
1.8 唯一索引
创建索引时提高unique:true的配置即可
db.collection.createIndex({title:1,type:1},{unique: true})
1.9 部分索引
部分索引也可以叫过滤索引,就是将索引进行条件过滤,符合条件的索引可以进行部分索引。
# 创建过滤索引
db.collection.createIndex(
{ cuisine: 1, name: 1 }, # 索引字段
{ partialFilterExpression: { rating: { $gt: 5 } } }
)
#使用过滤索引
#符合条件,使用索引
db.collection.find( { cuisine: "Italian", rating: { $gte: 8 } } )
#不符合条件,不能使用索引
db.collection.find( { cuisine: "Italian" } )
如果同时指定了partialFilterExpression和唯一约束,那么唯一约束只适用于满足筛选器表达式的文档
1.10 稀释索引
稀疏索引对存在索引字段的文档进行索引,不存在该字段的会过滤(对存在字段的文档进行索引(包括字段值为null的文档)
)。
#创建稀释索引(在选项位置添加sparse: true即可)
db.collection.createIndex( { "name": 1 }, { sparse: true } )
#可以和唯一索引一起使用
db.collection.createIndex({"name": 1},{sparse: true,unique:true})
#二者结合可以防止集合中存在字段值重复的文档,
#但允许不包含此索引字段的文档插入(满足稀释条件的唯一,不满足不唯一)。
1.11 TTL索引
对于随着时间推移,不再使用的数据要进行清理,以降低内存的消耗。我们要对这些数据进行老化处理,就需要给数据指定一个清理时间,常规解决方法有两个,一个是为每个数据指定一个时间戳定时清理,一个是将数据进行存表分类,之后对该表进行定时清理。而MongoDB提供给TTL索引,我们只需要声明在一个日期类型的字段中,TTL 索引是特殊的单字段索引。
# TTL索引标识(expireAfterSeconds: 3600 ) 指定expireAfterSeconds
db.collection.createIndex( { "lastModifiedDate": 1 }, { expireAfterSeconds: 3600 } )
#可以进行更改过期时间
db.runCommand({collMod:"集合名称",index:{keyPattern:{createdAt:1},expireAfterSeconds:600}})
1.12 隐藏索引
隐藏索引的好处就是对部分带有负面影响的索引进行隐藏
#创建隐藏索引
db.collection.createIndex({ borough: 1 },{ hidden: true });
# 现有隐藏索引
db.collection.hideIndex( { borough: 1} );
#取消隐藏索引
db.scores.unhideIndex( { userid: 1} )
2.索引执行情况
在查询的过程中,我们需要去清理我们是否使用了索引以及索引起到了什么样的效果,这个时候我们就需要通过explain()去获取数据扫描的情况。
verbose参数如下:
db.collection.find().explain(<verbose>)
stage的状态可以判断出是否使用了索引进行扫描
使用的时候尽量不要出现以下的stage:
- COLLSCAN(全表扫描)
- SORT(使用sort但是无index)
- 不合理的SKIP
- SUBPLA(未用到index的$or)
- COUNTSCAN(不使用index进行count)