linuxsir首页 LinuxSir.Org | Linux、BSD、Solaris、Unix | 开源传万世,因有我参与欢迎您!
网站首页 | 设为首页 | 加入收藏
您所在的位置:主页 > Linux数据库 >

MongoDB 存储引擎和数据模型设计

时间:2016-11-11  来源:未知  作者:linuxsir首页

MongoDB 存储引擎和数据模型设计

  • 1. 存储引擎
    • 1.1 存储引擎是什么
    • 1.2 MongoDB中的默认存储引擎
  • 2. 数据模型设计
    • 2.1 内嵌和引用
    • 2.2 设计原则
      • A. 1 - 1 或者 1 - *(较少)
      • B. 1 - *(较多)
      • C. 1 - *(非常多)
      • D. * - *
      • E. 通用建议

1. 存储引擎

1.1 存储引擎是什么

存储引擎是位于持久化数据(通常是放在磁盘或者内存中)和数据库之间的一个操作接口,它负责数据的存储和读取方式。MongoDB数据库通过存储引擎在磁盘中读取数据,而假设我们的应用是ASP.NET MVC,我们可以使用官方的Mongo.Driver驱动,通过通信协议(如TCP)向MongoDB数据库发送各种请求。以下是一个简单的运行图示

1.2 MongoDB中的默认存储引擎

自MongoDB 3.2 Release版本起,MongoDB默认的存储引擎就成了WiredTiger。而在之前的版本中,它还是MMAPv1。但由于,ongoDB架构支持可插拔的存储引擎,所以使用中即便要更换也是可以做到的。至于其他的功能比较大家可以参阅官方文档,如不再是In-Place Update,新增Compression等。

我们可以在开启mongod服务时输入相关参数调整存储引擎,如mongod --storageEngine MMAPv1|wiredTiger
我们也可以使用db.collections.stats()查看当前的引擎名称

  • MMAPv1
    MMAPv1 提供集合级别锁(实际上称为collection-level locking)

  • WiredTiger
    WiredTiger 对于写操作提供文档级别并发控制(实际上称为document-level concurrency),因此,不同的客户端请求可以在同一时间针对一个集合中的不同文档记性修改

2. 数据模型设计

2.1 内嵌和引用

在MongoDB中,数据的表示方式有内嵌和引用两种。

“引用”我们比较好理解,是指将不同实体的数据分散不到不同的集合中,而在关系型数据库设计中就是将实体分别建立相应的模型表。如常见的“老师-学生”,“产品-标签”关系,只要实体间存在关系,就可以使用“引用”思想。

“内嵌”是一种反范式化的设计,指的是将每个文档所需的数据都嵌入到文档内部,我想举一个“用户-账户”的关系。我们知道在领域驱动设计中,“用户”是一个聚合根,每个用户对应一个账户,所以是“1对1”的一种关系,在关系型数据库设计中,大部分时候都会将这两者严格区分开来。但是在MongoDB中,却不然,我们可以直接选择将“用户”需要的“账户”数据内嵌到用户文档中,便于我们的增删改查。这是一种反范式化的设计。

设计MongoDB数据模型的时候,我们需要转变以往设计关系型数据模型时的思维。即便是针对一个关系中不同集合的数量规模,我们的模型也将有很大的不同。

2.2 设计原则

**

A. 1 - 1 或者 1 - *(较少)

**

用户与账户,以及用户与收货地址都是这样情况,在这样的情况下,显而易见我们可以采取内嵌的方式来进行数据管理。

> db.person.findOne()
{
    _id:ObjectId("cccc"),
    name:"wddpct",
    age:22,
    location:"wenzhou",
    addresses:[
        {country:"china",city:"wenzhou",street:"chashan road"}
        {country:"china",city:"wenzhou",street:"north center road"}
    ]
}

这也引伸出一个问题,除了“1”以外的另一端的实体是否有必要在数目较少的时候进行单独集合的储存。如用户和任务模块,任务是系统定期发布,分配给相应用户完成,这意味着我们对任务的操作也将比较复杂。这样的情况下,显然是分开不同集合进行存储,然后让person集合引用task_id数组。

> db.person.findOne()
{
    _id:ObjectId("cccc"),
    name:"wddpct",
    age:21,
    location:"wenzhou",
    tasks:[
        ObjectId("xxxx"),
        ObjectId("yyyy"),
        ……
    ]
}

所以针对刚才提到的情况,我们大可以借鉴领域驱动模式中的“实体”和“值对象”的部分概念,主要还是看这些数据模型在系统中是否有较大较复杂的操作可能。

**

B. 1 - *(较多)

**

博主之前负责过一个市级地区中小学眼视光筛查系统,里面的简化模型就比较适合拿来做例子。如学校与学生,数目多也不过数千。这样的情况下,自然也是使用引用的方式更容易接受

> db.school.findOne()
{
    _id:ObjectId("cccc"),
    name:"middle1",
    location:"wenzhou",
    students:[
        ObjectId("xxxx"),
        ObjectId("yyyy"),
        ……
    ]
}

这里同样也引伸出一个“冗余”的问题,我们知道大多时候我们需要查询的数据属性数目是比较少的,比如对于学生而言,我们可能只需要知道他的身高体重,所以我们可以使用“冗余”思想简单修改刚才的集合成以下格式来应付

> db.school.findOne()
{
    _id:ObjectId("cccc"),
    name:"middle1",
    location:"wenzhou",
    students:[
        {ObjectId("xxxx"),name:"wddpct",height:233,weight:233},
        {ObjectId("yyyy"),name:"wddmd",height:233,weight:233}
        ……
    ]
}

不过也要注意的一点是,这样每次更新student的信息时,不免又要对school中的冗余信息进行更新,所以也要结合具体场景使用

**

C. 1 - *(非常多)

**

地区和车牌的关系勉强属于此类,一个地区可能有几十上百万车牌,我们不可能再像刚才那样在area中加入所有的license_id,不然可能光是单个文档大小就超过MongoDB的16MB限制了,而且对于查询也存在很大的负担。

这里我们可以直接套用关系型数据库中的外键思想,在license集合的末尾加入area_id就可以方便解决此类关系

> db.license.findOne()
{
    _id:ObjectId("cccc"),
    license:"middle1",
    area:ObjectId("xxxx")
}

当然,我们也可以对area进行进一步冗余,所以就不额外说明了。

**

D. * - *

**

对于多对多关系模型,可能又要祭出那句老话——“视具体情况而定”。不过一般情况下,它不过就是一对多关系的几个变种。一个基本的原则是考虑两边统一引用对方的ObjectId,适当冗余部分信息。

除此以外,我们还可以从以下几个原则去考虑

  1. 两边的数量比(较大方更适合引用)
  2. 两边的更新频率比(较大方更适合引用)
  3. 两边的读取频率比(较大方更适合内嵌)
    ……

E. 通用建议

以下给出一张较通用的建议表,仅供参考

内嵌引用
子文档较小 子文档较大
数据不会定期更改 数据经常改变
最终数据一致即可 中间阶段数据也必须一致
文档数据小额增加 文档数据大幅增加
数据通常需要执行二次查询 数据通常不包含在查询结果中
快速读取 快速写入

更多MongoDB相关教程见以下内容

CentOS 编译安装 MongoDB与mongoDB的php扩展 http://www.linuxidc.com/Linux/2012-02/53833.htm

CentOS 6 使用 yum 安装MongoDB及服务器端配置 http://www.linuxidc.com/Linux/2012-08/68196.htm

Ubuntu 13.04下安装MongoDB2.4.3 http://www.linuxidc.com/Linux/2013-05/84227.htm

MongoDB入门必读(概念与实战并重) http://www.linuxidc.com/Linux/2013-07/87105.htm

Ubunu 14.04下MongoDB的安装指南 http://www.linuxidc.com/Linux/2014-08/105364.htm

《MongoDB 权威指南》(MongoDB: The Definitive Guide)英文文字版[PDF] http://www.linuxidc.com/Linux/2012-07/66735.htm

Nagios监控MongoDB分片集群服务实战 http://www.linuxidc.com/Linux/2014-10/107826.htm

基于CentOS 6.5操作系统搭建MongoDB服务 http://www.linuxidc.com/Linux/2014-11/108900.htm

MongoDB 的详细介绍:请点这里
MongoDB 的下载地址:请点这里

友情链接
  • Mozilla发布Firefox 67.0.4,修复沙箱逃逸漏洞
  • 蚂蚁金服正式成为CNCF云原生计算基金会黄金会员
  • Firefox 68将采用Microsoft BITS安装更新
  • OpenSSH增加对存储在RAM中的私钥的保护
  • 谷歌想实现自己的curl,为什么?
  • Raspberry Pi 4发布:更快的CPU、更大的内存
  • Firefox的UA将移除CPU架构信息
  • Ubuntu放弃支持32位应用程序实属乌龙,Steam会否重回Ubuntu怀抱
  • Qt 5.13稳定版发布:引入glTF 2.0、改进Wayland以及支持Lottie动
  • 红帽企业Linux 7现已内置Redis 5最新版
  • Slack进入微软内部禁用服务清单,GitHub也在其列?
  • 安全的全新编程语言V发布首个可用版本
  • Windows Terminal已上架,快尝鲜
  • 阿里巴巴微服务开源生态报告No.1
  • 面世两年,Google地球将支持所有基于Chromium的浏览器
  • 推进企业容器化持续创新,Rancher ECIC千人盛典完美收官
  • CentOS 8.0最新构建状态公布,或于数周后发布
  • Debian移植RISC
  • 微软拆分操作系统的计划初现雏形
  • Oracle发布基于VS Code的开发者工具,轻松使用Oracle数据库
  • Ubuntu 19.10停止支持32位的x86架构
  • 微软为Windows Terminal推出全新logo
  • 联想ThinkPad P系列笔记本预装Ubuntu系统
  • 微软发布适用于Win7/8的Microsoft Edge预览版
  • 启智平台发布联邦学习开源数据协作项目OpenI纵横
  • 经过六个多月的延迟,微软终于推出Hyper
  • ZFS On Linux 0.8.1 发布,Python可移植性工作
  • DragonFly BSD 5.6.0 发布,HAMMER2状态良好
  • Linux Kernel 5.2
  • CentOS 8.0 看起来还需要几周的时间
  • 百度网盘Linux版正式发布
  • PCIe 6.0宣布:带宽翻倍 狂飙至256GB/s
  • PHP 7.4 Alpha 发布,FFI扩展,预加载Opcache以获得更好的性能
  • Canonical将在未来的Ubuntu版本中放弃对32位架构的支持
  • Scala 2.13 发布,改进的编译器性能
  • 微软的GitHub收购了Pull Panda,并且使所有订阅完全免费
  • Windows Subsystem for Linux 2 (WSL 2)现在适用于Windows 10用
  • Debian 10 “Buster”的RISC
  • MariaDB宣布发布MariaDB Enterprise Server 10.4
  • DXVK 1.2.2 发布,带来微小的CPU开销优化
  • DragonFlyBSD 5.6 RC1 发布,VM优化,默认为HAMMER2
  • PrimeNG 8.0.0 发布,支持Angular 8,FocusTrap等
  • GIMP 2.10.12 发布,一些有用的改进
  • 清华大学Anaconda 镜像服务即将恢复
  • Debian GNU/Linux 10 “Buster” 操作系统将于2019年7月6日发布
  • 时时彩论坛
  • 五星体育斯诺克
  • 北单比分直播
  • 河北11选5走势图
  • 福建体彩36选7开奖结果
  • 九龙图库下载