文档模型
文档模型
支持文档数据模型的主要论据是架构灵活性,因局部性而拥有更好的性能,以及对于某些应用程序而言更接近于应用程序使用的数据结构。关系模型通过为连接提供更好的支持以及支持多对一和多对多的关系来反击。如果应用程序中的数据具有类似文档的结构(即,一对多关系树,通常一次性加载整个树
局限性
文档模型有一定的局限性:例如,不能直接引用文档中的嵌套的项目,而是需要说“用户
但是,如果你的应用程序确实使用多对多关系,那么文档模型就没有那么吸引人了。通过反规范化可以减少对连接的需求,但是应用程序代码需要做额外的工作来保持数据的一致性。通过向数据库发出多个请求,可以在应用程序代码中模拟连接,但是这也将复杂性转移到应用程序中,并且通常比由数据库内的专用代码执行的连接慢。在这种情况下,使用文档模型会导致更复杂的应用程序代码和更差的性能。
很难说在一般情况下哪个数据模型让应用程序代码更简单;它取决于数据项之间存在的关系种类。对于高度相联的数据,选用文档模型是糟糕的,选用关系模型是可接受的,而选用图形模型是最自然的。
架构灵活性
大多数文档数据库以及关系数据库中的
读时模式类似于编程语言中的动态(运行时)类型检查,而写时模式类似于静态(编译时)类型检查。就像静态和动态类型检查的相对优点具有很大的争议性一样,数据库中模式的强制性是一个具有争议的话题,一般来说没有正确或错误的答案。
在应用程序想要改变其数据格式的情况下,这些方法之间的区别尤其明显。例如,假设你把每个用户的全名存储在一个字段中,而现在想分别存储名字和姓氏。在文档数据库中,只需开始写入具有新字段的新文档,并在应用程序中使用代码来处理读取旧文档的情况。例如:
if (user && user.name && !user.first_name) {
// Documents written before Dec 8, 2013 don't have first_name
user.first_name = user.name.split(" ")[0];
}
另一方面,在“静态类型”数据库模式中,通常会执行以下 迁移(migration)操作:
ALTER TABLE users ADD COLUMN first_name text;
UPDATE users SET first_name = split_part(name, ' ', 1); -- PostgreSQL
UPDATE users SET first_name = substring_index(name, ' ', 1); -- MySQL
大多数关系数据库系统可在几毫秒内执行
大型表上运行
- 存在许多不同类型的对象,将每种类型的对象放在自己的表中是不现实的。
- 数据的结构由外部系统决定。你无法控制外部系统且它随时可能变化。
在上述情况下,模式的坏处远大于它的帮助,无模式文档可能是一个更加自然的数据模型。但是,要是所有记录都具有相同的结构,那么模式是记录并强制这种结构的有效机制。
查询的数据局部性
文档通常以单个连续字符串形式进行存储,编码为
局部性仅仅适用于同时需要文档绝大部分内容的情况。数据库通常需要加载整个文档,即使只访问其中的一小部分,这对于大型文档来说是很浪费的。更新文档时,通常需要整个重写。只有不改变文档大小的修改才可以容易地原地执行。因此,通常建议保持相对小的文档,并避免增加文档大小的写入。这些性能限制大大减少了文档数据库的实用场景。
值得指出的是,为了局部性而分组集合相关数据的想法并不局限于文档模型。例如,
文档模型与关系模型的融合
自
在文档数据库中,