对于MongoDB,面临的最大问题就是如何为应用程序设计出良好的数据模型,大家都是摸着石头过河,意见很难达成一致。最近读了O‘REILLY的一本小册子《50 Tips & Tricks for MongoDB Developers》受益匪浅,所以决定将其中的内容翻译出来。并结合自己实际感受给予评注。
#第一条 为了速度去重复数据,为了完整性去引用数据(Duplicate data for speed,reference data for integrity)
多个文档中的数据能够被“嵌入”(embed)或是“引用”(reference)。很难说“嵌入”的方式就一定比“引用”好,反之亦然。每种方式都有自己用处,而你应该为你的应用程序去选择合适的方式。
“嵌入”会引起数据的“不一致”:假设你想把(图1.1)中的苹果变成梨,如果你更改了其中一个文档中的值,但恰巧在就要更改第二个文档的值之前系统崩溃了,那么你的数据库中对于fruit会出现两个不同的值。
图1.1
“不一致”并不是件好事,但是“不好”的程度取决于你存储的是什么。在许多应用中,短暂的“不一致”是被允许的:例如某人修改他的用户名,他并不会介意在几个小时内他的旧文章中仍然显示其旧用户名。如果连短期内的不一致都不被允许,这时你需要考虑“引用”了。
然而,如果你“引用”,那么你的应用程序就必须做额外的查询去找出这个水果是什么(图1.2),如果你的应用不能这样的性能打击或是具备稍后将数据一致化的能力,那么你一改使用“嵌入”。
这是一种权衡:你不可能同时具有“最快性能”(fastest performance)和“即刻一致性”(guaranteed immediate
consistency)。你必须去决定哪个对你的应用来说更重要。
例子:购物车订单
假设我们在为一个购物车应用设计数据模型。我们的应用将订单存储在MongoDB中,那么一个订单中应该包含什么样的信息呢?
“引用”模式:
A product:
{
"_id" : productId,
"name" : name,
"prise" : price,
"desc" : description
}
An order:
{
"_id" : orderId,
"user" : userInfo,
"items" : [
productId1,
productId2,
productId3
]
}
我们将所定产品的_id存储在[订单]文档的“items”集合中。然后,当我们需要显示订单内容的时候,我们去查询[订单]文档来获取正确的订单,然后通过“items”中的产品_ids去[产品]文档中查询与之相关的每个产品。“引用”模式中,我们没有办法通过单次查询来获取到全部的订单内容。
如果产品信息被更新,所有引用该产品的文档都会跟着“改变”,因为这些文档中存储的仅仅只是产品的引用。
“嵌入”模式
A product(和“引用”模式中的相同):
{
"_id" : productId,
"name" : name,
"prise" : price,
"desc" : description
}
An order:
{
"_id" : orderId,
"user" : userInfo,
"items" : [
{
"_id" : productId1,
"name" : name1,
"price" : price1,
"desc" : description1
},
{
"_id" : productId2,
"name" : name2,
"price" : price2,
"desc" : description2
},
{
"_id" : productId3,
"name" : name3,
"price" : price3,
"desc" : description3
}
]
}
我们将产品信息当做嵌入到[订单]文档中,然后,当我们要显示订单的时候,只需要做一次查询。
如果一个产品的信息被更新,并且需要将订单中的产品同时更新,我们需要分别去更新每个订过该产品的[订单]文档。“嵌入”使得我们能够更快的读取,但是产品信息不能够在多个文档中被原子性的改变。
因此,给出一些选项,帮助你决定使用“引用”还是“嵌入”?
决定因素
有三个主要因素需要考虑:
1.你是否为了很少才会发生一次的数据变化而在每次读取上花费代价。
你也许会去读取一个产品一万次为了它的每一次变化。你是否会愿意每次为了”使一次写入更快或是保证一致性而去做10000次读取”缴纳罚金。大多数的应用程序read-heavy比write-heavy要重要一些:做出你的权衡吧。
2.一致性对你的应用来讲有多重要?
如果你的应用中一致性很重要,你应该采用"引用"模式,例如,我们需要多个文档原子性的看到一次数据变化。 如果我们做的是一个只能在某些时间段内交易某种"有价证券"的交易系统,当"有价证券"不可交易时,我们应该立即对它 们加"锁"。我们可以将一个加锁的单个文档引用到一组与之相关的[有价证券]文档中。这样做要比在应用程序层面上去加 锁要好一点。但是无论如何,应用程序需要知道何时去加锁以及何时去解锁。
3.是否需要快速读取?
如果读取需要尽可能的快,那么应该采用"嵌入"。在实时(Real-time)系统中应该尽可能的使用"嵌入"。
- 大小: 19.4 KB
- 大小: 19.4 KB
- 大小: 16.4 KB
分享到:
相关推荐
《MongoDB developers》 原书高清版本,希望你喜欢
文档与操作手册:为了方便他人理解和使用我的作品,我编写了详细的操作手册和使用说明,同时提供了一份Markdown格式的文档,概述了项目的主要功能和特点。 学习笔记:在项目开发过程中,我记录了大量的学习笔记和...
Mongolayer是类似于Mongoose的功能丰富的文档系统,但是更薄,类型更严格,并且具有更大的开发者灵活性。 该模块旨在提供mongoose的视觉效果(验证,勾子,关系),但具有较少的怪异性,较少的底层魔术,可为开发...
A Guide to Porting C C++ to Rust.epub Build a Node.js Project from Scratch.epub Build your applications with Webpack....给iOS开发者的Sketch入门教程.epub 编写高质量代码改善 Python 程序的 91 个建议.epub
除了实时推送架构,RethinkDB 还有许多胜过 MongoDB的地方:一种高级的查询语言,能够支持table joins, subqueries 和大规模并行式分布计算。融合了查询语言的操作和监控API,大幅度降低了RethinkDB扩展的难度。简洁...
6. 客服与反馈:提供在线客服和反馈系统,解答用户疑问,收集用户建议。 **三、技术实现** 项目基于微信小程序原生开发,采用JavaScript、WXML、WXSS等技术进行编程。后端采用腾讯云开发,实现数据的存储和服务器...
基于Spring Boot在线远程考试系统的设计与实现是一个面向教育机构和企业培训的应用程序,旨在提供一个稳定、高效且易于使用的...如需获取关于特定项目的详细信息,建议直接查阅该项目的文档或联系开发者获取更多资源。
这是一个关于计算机专业毕业设计的微信小程序案例资源包,主题为“健康早知道”。该资源包括论文、毕设源码和详细的说明文档,旨在帮助学习者更好地理解和实现一个基于微信小程序的健康信息推送系统。 在这个资源包...
Hydro是一个高效的信息学在线测评系统。特点:易于部署(且提供安装脚本),轻量,功能强大且易于扩展。 欢迎star本项目,这是对开发者的鼓励。项目的开发与维护需要资金,欢迎进行逐步。 Hydro提供收费的功能定制...
dnnmmp是基于docker的开发者集成环境...Node.js:建议所有开发者学习的语言 PHP:世界上最好的语言 Mysql:数据库 MongoDB:数据库 Redis:数据库 Nginx:服务器 Portainer:docker管理工具 rabbitmq:队列服务
dnnmmp是基于docker的开发者集成环境,包含...Node.js:建议所有开发者学习的语言 PHP:世界上最好的语言 Mysql:数据库 MongoDB:数据库 Redis:数据库 Nginx:服务器 Portainer:docker管理工具 rabbitmq:队列服务
流星最佳实践嘿,流星开发者! 欢迎来到流星知识的这个不起眼的地方 :smiling_face_with_smiling_eyes: 本指南旨在帮助Meteor开发人员分享他们的最佳实践,以构建最高效,最强大的Meteor应用程序。 这里提供的信息...