非关系数据库设计

我很想听听你在 非关系型“ nosql”数据库中使用的设计策略——也就是说,不使用传统关系设计或 SQL 的数据存储类(比如 Hypertable、 CouchDB、 SimpleDB、 Google App Engine 数据存储、 Voldemort、 Cassandra、 SQL Data Services 等)。它们也经常被称为“键/值存储”,基本上它们就像巨大的分布式持久哈希表。

具体来说,我想了解 概念数据设计概念数据设计与这些新数据库之间的差异。什么更容易,什么更难,什么根本做不到?

  • 你有没有想出在非关系世界中更好的替代设计?

  • 你有没有碰过什么看起来不可能的东西?

  • 你是否已经在设计模式之间架起了桥梁,例如从一种模式转换到另一种模式?

  • Do you even do explicit data models at all now (e.g. in UML) or have you chucked them entirely in favor of semi-structured / document-oriented data blobs?

  • 您是否错过了 RDBMS 提供的主要额外服务,如关系完整性、任意复杂的事务支持、触发器等?

我来自一个 SQL 关系数据库背景,所以标准化是我的血液。也就是说,我得到了非关系数据库在简单性和可伸缩性方面的优势,我的直觉告诉我,设计功能必须有更丰富的重叠。你做了什么?

仅供参考,StackOverflow 在这里也讨论过类似的话题:

21118 次浏览

I'm answering this with CouchDB in the back of my mind, but I would presume most would be true for other DBs also. We looked at using CouchDB, but finally decided against it since our data access is not known beforehand and scalability is not the issue.

更难:

  • 需要在概念层面上重新思考,因为它是不同的,所以它是“困难的”。由于您必须事先了解数据访问模式,因此不能应用自动转换。您至少需要添加访问模式。
  • Consistency is not handled by the database but must be dealt with in the application. Less guarantees means easier migration, fail-over and better scalability at the cost of a more complicated application. An application has to deal with conflicts and inconsistencies.
  • 跨文件(或键/值)的链接也必须在应用程序级别处理。
  • SQL 类型的数据库具有更加成熟的 IDE。您得到了许多支持库(尽管这些库的分层使得事情比 SQL 所需要的复杂得多)。

更简单:

  • 如果您知道数据访问模式,那么速度会更快。
  • 对于数据库来说,迁移/故障转移更容易,因为作为应用程序程序员,没有对您作出任何承诺。虽然你有最终一致性。也许吧。终于来了。有一段时间了。
  • 一个键/值比表中的一行更容易理解。所有的(树)关系都已经存在,并且可以识别完整的对象。

建模应该是相同的,但是您必须注意您在一个文档中放入了什么: UML 也可以用于面向对象建模和数据库建模,它们已经是两种不同的动物了。

我希望看到一个良好的开放式 OO 数据库与 C #/Silverlight 很好地集成。让选择变得更加困难。:)

长期以来,对于任何大小的数据集来说,平面文件都被认为是晦涩难懂和不切实际的。然而,具有更多内存的更快的计算机可以将文件加载到内存中并实时对其进行排序,至少对于相当小的 n 和本地的单用户应用程序是这样的。

例如,您通常可以读取一个包含10,000条记录的文件,并在不到半秒的时间内对其进行排序,这是一个可接受的响应时间。

当然,使用数据库代替平面文件是有原因的——关系操作、数据完整性、多用户能力、远程访问、更大的容量、标准化等等,但计算机速度和内存容量的提高使得在内存中操作数据在某些情况下更加实用。

我认为必须考虑到非关系数据库管理系统在数据模型方面有很大的不同,因此概念数据设计也会有很大的不同。在 NOSQL Google groupData Design in Non-Relational Databases线程中,不同的范例分类如下:

  1. 类大表系统(HBase, 极度敏感等)
  2. 键值商店(东京,伏地魔, 等)
  3. 文档数据库(CouchDB, MongoDB, etc)
  4. 图形数据库(AllegroGraph, Neo4j, Sesame, etc)

我大部分时间都在使用 图形数据库,正是使用这个范例的优雅的数据设计带我来到这里,厌倦了 关系数据库的缺点。我已经在这个 维基页面上放了一些使用图形数据库进行数据设计的例子,还有一个 如何建模的例子,基本的 IMDB电影/演员/角色数据。

马尔科 · 罗德里格斯制作的演示幻灯片(幻灯片共享) 图形数据库与大规模知识管理的未来包含了使用图形数据库进行数据设计的非常好的介绍。

从图表的角度回答具体问题:

替代设计: 添加许多不同类型的实体之间的关系,而不用担心或预先定义哪些实体可以连接。

弥合差距: 我倾向于根据领域本身对每种情况做不同的处理,因为我不想要“面向表的图”之类的东西。但是,这是提供了一些关于从 RDBMS 自动转换到 Graphdb 的信息。

显式数据模型: 我一直这样做(白板风格) ,然后使用数据库中的模型。

来自 RDBMS 世界的遗漏: 创建报表的简单方法。更新: 也许从图形数据库创建报告并不困难,请参阅 Creating a Report for a Neo4J Sample Database

我刚刚开始使用非关系数据库,我仍然试图理解它,并找出最佳模型。我只能代表 CouchDB 说话。

不过,我还是得出了一些初步结论:

你有没有想出在非关系世界中更好的替代设计?

设计重点转移: 文档模型(对应于 DB 表)的设计几乎变得无关紧要,而一切都取决于视图的设计(对应于查询)。

文档数据库可以交换复杂性: SQL 有不灵活的数据和灵活的查询,而文档数据库恰恰相反。

CouchDB 模型是“ JSON 文档”(基本上是嵌套的散列表)的集合。每个文档都有一个唯一的 ID,可以通过 ID 进行简单的检索。对于任何其他查询,您都需要编写“ views”,它是一组名为 map/reduce 的函数。视图以键/值对列表的形式返回结果集。

诀窍在于,不要像查询 SQL 数据库那样查询数据库: 运行视图函数的结果存储在索引中,只能查询索引。(比如“获取一切”、“获取键”或“获取键范围”。)

SQL 世界中最接近的类比是,如果您只能使用存储过程来查询数据库,那么您想要支持的每个查询都必须是预定义的。

这些文件的设计非常灵活,我发现只有两个限制:

  • 将相关数据放在同一个文档中,因为没有与连接对应的数据。
  • 不要把文档做得太大,以至于太频繁地更新它们(比如把所有公司当年的销售额放在同一个文档中) ,因为每次文档更新都会触发重新索引。

但一切都取决于景观的设计。

我发现,与任何 SQL 数据库相比,CouchDB 的替代设计在系统层面(而非存储层面)的数量级更好。如果你有一些数据,并希望将它们提供给一个网页,那么整个系统的复杂性至少降低了50% :

  • 没有设计数据库表
  • 没有 ODBC/JDBC 中间层,所有查询和事务通过 http (moderate issue)
  • 从 JSON 到对象的简单数据库映射,与 SQL(重要!)中的相同映射相比,这几乎是微不足道的
  • 您可以跳过整个应用程序服务器,因为您可以使用 AJAX 将文档设计为由浏览器直接检索,并在将其显示为 HTML 之前添加一些 JavaScript 修饰。(巨大的! !)

对于普通的 webapps 来说,基于文档/JSON 的数据库是一个巨大的胜利,而不太灵活的查询和一些额外的数据验证代码的缺点似乎是一个很小的代价。

Have you hit your head against anything that seems impossible?

还没有。Map/reduce 作为查询数据库的一种方法是不熟悉的,并且需要比编写 SQL 更多的思考。原语的数量相当少,因此获得所需的结果主要是如何创造性地指定键的问题。

有一个限制是查询不能同时查看两个或多个文档——没有连接或其他类型的多文档关系,但到目前为止还没有什么是不可克服的。

作为示例限制,计数和求和很容易,但是 CouchDB 视图/查询无法计算平均值。解决方案: 分别返回和和计数并计算客户端的平均值。

你是否已经在设计模式之间架起了桥梁,例如从一种模式转换到另一种模式?

我不确定这是否可行。它更像是一个完全的重新设计,就像将函数式样式程序转换成面向对象的样式一样。一般来说,文档类型比 SQL 表少得多,每个文档中的数据也多得多。

考虑这个问题的一种方法是查看 SQL 中的插入和常见查询: 例如,当客户下订单时,哪些表和列会被更新?哪些是月度销售报告?这些信息应该放在同一个文档里。

也就是说: 一个针对 Order 的文档,包含客户 ID 和产品 ID,并根据需要复制字段以简化查询。文档中的任何内容都可以轻松查询,任何需要在 Order 和 Customer 之间进行交叉引用的内容都必须由客户机完成。因此,如果您想要一份按地区分列的销售报告,您可能应该在订单中输入一个地区代码。

你现在有没有做过明确的数据模型(例如,在 UML 中) ?

对不起,在文档 DBs 之前也没有做过很多 UML:)

但是您需要某种模型来说明哪些字段属于哪些文档,以及它们包含哪些类型的值。这些都是为了以后的参考,也是为了确保每个使用 DB 的人都知道这些约定。例如,如果将日期存储在文本字段中,并且任何人都可以添加或删除他们喜欢的任何字段,那么就不会再出现错误,因此需要验证代码和约定来弥补这一缺陷。特别是当你使用外部资源的时候。

您是否怀念 RDBMS 提供的主要额外服务?

Nope. But my background is web application developer, we deal with databases only to the extent that we must :)

我曾经工作过的一家公司开发了一个产品(一个网络应用程序) ,该产品可以在来自多个供应商的 SQL 数据库中运行,而“额外的服务”在不同的数据库之间是如此的不同,以至于它们必须为每个数据库分别实现。因此,将功能移出 RDBMS 对我们来说工作较少。这甚至延伸到全文搜索。

所以无论我放弃什么都是我从来没有过的。显然,你的经历可能不同。


A caveat: What I am working on now is a webapp for financial data, stock quotes and the like. This is a very good match for a document DB, from my point of view I get all the benefits of a DB (persistence and queries) without any of the hassle.

But these data are fairly independent of each other, there are no complex relational queries. Get latest quotes by ticker, get quotes by ticker and date range, get company meta-info, that's pretty much all of it. Another example I saw was a blog application, and blogs are not characterized by massively complicated database schemas either.

我想说的是,我所知道的所有成功的文档数据库应用程序都是使用一开始就没有太多相互关系的数据: 文档(如谷歌搜索)、博客文章、新闻文章、金融数据。

我希望有一些数据集能够更好地映射到 SQL,而不是文档模型,所以我认为 SQL 会生存下来。

但是对于我们这些只想用简单的方法存储和检索数据的人来说,文档数据库(就像 CouchDB 一样)是天赐之物。

与您的说法相反,我在现实生活中看到的关系数据库往往没有很好地规范化。当被问及时,设计师告诉我这主要是因为性能。RDBM 不善于连接,因此从规范化的角度来看,表往往过于宽泛。面向对象数据库在这方面往往做得更好。

Another point where RDBMs have problems is handling history/time-dependent keys.