问:内部的存储结构?
答:bson
问:为什么mongodb会选择bson,bjson与json有什么区别?
答:首先json比较普遍,其次bson的效率由于json,(1)类似于redis的len字段,bson会把每个元素的len字段存在头部,优化了遍历速度,读取数据的时候可以直接跳到该元素那里进行读取(2)对json来说操作是无类型的,9和10的性能是不一样的一个字符和两个字符的区别,但是buson不会,类似于redis的整数型数据类型,长度不变,只是改变了值
问:怎么实现事务的
答:MongoDB3.0支持单文档事务,基于WiredTiger引擎,保证数据,索引,oplog三者的原子性
问:MongoDB实现事务的难点在于时序问题
答:MongoDB 通过 oplog 时间戳来标识全局顺序,而 WiredTiger 通过内部的事务ID来标识全局顺序,在实现上,2者没有任何关联。这就导致在并发情况下, MongoDB 看到的事务提交顺序与 WiredTiger 看到的事务提交顺序不一致。这种情况下,MongoDB4.0中WiredTiger只能做调整,加入时间戳transaction timestamp;
在 3.x 版本里,一个写请求对数据、索引、oplog的修改会放到一个 WT 事务里,事务的提交由 MongoDB 自己控制,MongoDB 会尽可能快的提交事务,完成写清求;但 4.0 引入事务之后,事务的提交由应用程序控制,可能出现一个事务修改很多,并且很长时间不提交,这会给 WT cache evict 造成很大的影响,如果大量内存无法 evict,最终就会进入 cache stuck 状态。为了尽量减小 WT cache 压力,MongoDB 4.0 事务功能有一些限制,但事务资源占用超过一定阈值时,会自动 abort 来释放资源。
问:一个事务中文档数可以非常大吗?一个事务操作最大允许时间是多大?
答:(1)事务的生命周期不能超过 transactionLifetimeLimitSeconds
(默认60s),该配置可在线修改,(2)事务修改的文档数不能超过 1000 ,不可修改
问:事务如何回滚?
答:在 3.x 版本里,MongoDB 的节点需要回滚时,会根据要回滚的 oplog 不断应用相反的操作,或从回滚源上读取最新的版本,整个回滚操作效率很低。
4.0 版本实现了存储引擎层的回滚机制,当复制集节点需要回滚时,直接调用 WiredTiger 接口,将数据回滚到某个稳定版本(实际上就是一个 Checkpoint),这个稳定版本则依赖于 stable timestamp
。WiredTiger 会确保 stable timestamp
之后的数据不会写到 Checkpoint里。
问:MongoDB持久化策略?
答:在MongoDB启动的时候,会开启一个线程去循环将数据写入磁盘,但是写的方式是有一定时间周期,异步延迟去写
问:mongodb的存储引擎是什么?
答:MongoDB目前支持的存储引擎为内存映射引擎。当MongoDB启动的时候,会将所有的数据文件映射到内存中,然后操作系统会托管所有的磁盘操作。这种存储引擎有以下几种特点:
* MongoDB中关于内存管理的代码非常精简,毕竟相关的工作已经有操作系统进行托管。
* MongoDB服务器使用的虚拟内存将非常巨大,并将超过整个数据文件的大小。不用担心,操作系统会去处理这一切。
问:为什么mongodb是面向集合的?自由的?文档型?
答:面向集合:数据被分组到若干集合,这些集合称作聚集(collections);
自由的:数据库并不需要知道你将存入到聚集中的文档的任何结构信息.实际上,你可以在同一个聚集中存储不同结构的文档
文档型:我们存储的数据是键-值对的集合,键是字符串,值可以是数据类型集合里的任意类型,包括数组和文档. 我们把这个数据格式称作bson,可以存照片和视频;
面向文档的数据库用一个有组织的文件来存储数据,而不是用行来存储数据,在MongoDB中,一组文档被看作是一个集合,在关系数据库中,许多行的集合被看作是一张表。
像上面的一个结构,为一个文档(document),相当于关系数据库中的一行记录,多个文档组成一个集合(collection),相当于关系数据库的表。多个集合(collection),逻辑上组织在一起,就是数据库(database),一个MongoDB实例支持多个数据库(database)。
问:mongodb的设计有很多缺点,譬如?
答:(1)在32位系统上,不支持大于2.5G的数据
(2)单个文档大小限制为 4 M/16 M(1.8版本后升为16M)
(3)对内存要求比较大
(4)用户权限方面比较弱,这一点MongoDB官方推荐的是将机器部署在安全的内网环境中,尽量不要用权限
Wordnik:从MySQL到MongoDB:
https://blog.csdn.net/hzcyclone/article/details/7304293
问:mongodb的数据存在内存还是磁盘?
答:热点数据存在内存,其它数据存在磁盘,利用内存映射引擎做关联
问:单机的情况下为什么不建议用mongodb?
答:因为mongodb的持久化做的不好,宕机的时候会丢失一部分数据,因为持久化策略是延后一段时间写入磁盘
问:对于文档这种东西的存储如何更好地白话理解?
答:面向文档,那么什么是文档呢?很明显这不是我们常见的word文档。这里说的文档,是一种可以嵌套的数据集合。从关系数据库的范式的概念来说,嵌套是明显的反范式设计。范式设计的好处是消除了依赖,但是增加了关联,查询需要通过关联两张或者多张表来获得所需要的全部数据,但是更改操作是原子的,只需要修改一个地方即可。反范式则是增加了数据冗余来提升查询性能,但更新操作可能需要更新冗余的多处数据,需要注意一致性的问题。
一个典型的例子,如blog,关系数据库中一般可以把文章设计为一张表,评论设计为一张表,那么在页面需要展示一篇文章和其对应的评论的时候,就需要关联查询文章表和评论表。但是面向文档的设计,可以将评论作为文章的一个嵌套文档存放在一起,这不但省去了关联查询,由于存储在一起,查询的性能也可以做到更好。
MongoDB的面向文档采用的是BSON,一种类似JSON的格式,但是是二进制序列化的。如上面提到的blog的文章和评论,可以做如下设计:
{ 'id':1, 'author':'NinGoo', 'title':'白话MongoDB(一)', 'content':'按照官方的说法,此处省略一万字',
comment:[ {'comment-author':'宋兵甲', 'comment-content':'有木有' } ,
{'comment-author':'尼玛','comment-content':'伤不起啊' }
]
}
问:数据量过大超过16M,需要用到mongodb底层的GridFS直接作为文件存储,什么是GridFS?
答:
问:Modifier是什么?
答:Modifier也是MongoDB可以作为对用户行为跟踪的容器。在实际中使用Modifier来将用户的交互行为快速保存到MongoDB中以便后期进行统计分析和个性化定制。
问:Map/Reduce
Map/Reduce也是MongoDB中比较吸引人的特性。Map/Reduce可以对大数据量的表进行统计、分类、合并的工作,完成原先SQL的GroupBy等聚合函数的功能。并且Mapper和Reducer的定义都是用Javascript来定义服务端脚本。
问:mmap机制是什么?
答:MongoDB由于采用了mmap机制,如果索引和热数据能被内存完全装下,那么其操作基本上相当于内存操作,所以MongoDB的当机性能是相当高的。
问:mongodb支持关联查询码?
答:MongoDB提供与关系型数据库类似的各种数据操作(除了关联查询),其索引机制更是与关系型数据库几乎一模一样。同时MongoDB也提供MapReduce的操作接口,用以处理一些批量任务。
本文转载自火丁笔记,文章举了一个数据库设计的例子,对MySQL和MongoDB两种存储工具,分别进行了数据库结构设计,在MongoDB的设计上,利用了MongoDB的 schema-free的特性。
虽然文中的例子不一定是最优的选择。但分享此文,希望提醒大家,换个存储,不仅是换一个存储,更重要的是换一套思维。
MySQL是关系型数据库中的明星,MongoDB是文档型数据库中的翘楚。下面通过一个设计实例对比一下二者:假设我们正在维护一个手机产品库,里面除了包含手机的名称,品牌等基本信息,还包含了待机时间,外观设计等参数信息,应该如何存取数据呢?
如果使用MySQL话,手机的基本信息单独是一个表,另外由于不同手机的参数信息差异很大,所以还需要一个参数表来单独保存。
CREATE TABLE IF NOT EXISTS `mobiles` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` VARCHAR(100) NOT NULL,
`brand` VARCHAR(100) NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE IF NOT EXISTS `mobile_params` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`mobile_id` int(10) unsigned NOT NULL,
`name` varchar(100) NOT NULL,
`value` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
);
INSERT INTO `mobiles` (`id`, `name`, `brand`) VALUES
(1, 'ME525', '摩托罗拉'),
(2, 'E7' , '诺基亚');
INSERT INTO `mobile_params` (`id`, `mobile_id`, `name`, `value`) VALUES
(1, 1, '待机时间', '200'),
(2, 1, '外观设计', '直板'),
(3, 2, '待机时间', '500'),
(4, 2, '外观设计', '滑盖');
注:为了演示方便,没有严格遵守关系型数据库的范式设计。
如果想查询待机时间大于100小时,并且外观设计是直板的手机,需按照如下方式查询:
SELECT * FROM `mobile_params` WHERE name = '待机时间' AND value > 100;
SELECT * FROM `mobile_params` WHERE name = '外观设计' AND value = '直板';
注:参数表为了方便,把数值和字符串统一保存成字符串,实际使用时,MySQL允许在字符串类型的字段上进行数值类型的查询,只是需要进行类型转换,多少会影响一点性能。
两条SQL的结果取交集得到想要的MOBILE_IDS,再到mobiles表查询即可:
SELECT * FROM `mobiles` WHERE mobile_id IN (MOBILE_IDS)
如果使用MongoDB的话,应该如何存取数据呢?
如果使用MongoDB的话,虽然理论上可以采用和MySQL一样的设计方案,但那样的话就显得无趣了,没有发挥出MongoDB作为文档型数据库的优点,实际上使用MongoDB的话,和MySQL相比,形象一点来说,可以合二为一:
db.getCollection("mobiles").ensureIndex({
"params.name": 1,
"params.value": 1
});
db.getCollection("mobiles").insert({
"_id": 1,
"name": "ME525",
"brand": "摩托罗拉",
"params": [
{"name": "待机时间", "value": 200},
{"name": "外观设计", "value": "直板"}
]
});
db.getCollection("mobiles").insert({
"_id": 2,
"name": "E7",
"brand": "诺基亚",
"params": [
{"name": "待机时间", "value": 500},
{"name": "外观设计", "value": "滑盖"}
]
});
如果想查询待机时间大于100小时,并且外观设计是直板的手机,需按照如下方式查询:
db.getCollection("mobiles").find({
"params": {
$all: [
{$elemMatch: {"name": "待机时间", "value": {$gt: 100}}},
{$elemMatch: {"name": "外观设计", "value": "直板"}}
]
}
});
注:查询中用到的$all,$elemMatch等高级用法的详细介绍请参考官方文档中相关说明。
MySQL需要多个表,多次查询才能搞定的问题,MongoDB只需要一个表,一次查询就能搞定,对比完成,相对MySQL而言,MongoDB显得更胜一筹,至少本例如此。
问:ACID与BASE和区别?
答: 理解ACID与BASE的区别(ACID是关系型数据库强一致性的四个要求,而BASE是NoSQL数据库通常对可用性及一致性的弱要求原则,它们的意思分别是,ACID:atomicity, consistency, isolation, durability;BASE:BasicallyAvailable, Soft-state, Eventually Consistent。同时有意思的是ACID在英语里意为酸,BASE意思为碱)