7

我们正在使用 MySQL 来存储无模式数据(请参阅:使用关系数据库获取无模式数据以了解 FriendFeed 如何使用 MySQL 存储无模式数据的解决方案)。

一张大表包含我们应用程序的所有实体:

CREATE TABLE entities (
  added_id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY
, id BINARY(16) NOT NULL
, body MEDIUMBLOB
, UNIQUE KEY (id)
) ENGINE=InnoDB ;

一些细节:

  • 存储实体唯一需要的属性是id16 字节的 UUID。实体的其余部分对数据库是不透明的。我们可以简单地通过将新属性存储在body.

  • added_id列存在是因为 InnoDB 按主键顺序物理存储数据行。AUTO_INCREMENT 主键确保新实体在旧实体之后按顺序写入磁盘,这有助于读/写局部性(新实体的读取频率高于旧实体)。

  • 我们的数据库将无模式数据存储在body. <- 这是这个问题的主题。

  • 许多其他有趣的细节,比如“进入”body数据以构建异步物化视图(索引只是离线构建的表),但它们与当前的讨论无关......

我们应该如何序列化中的结构化数据(键值对)body

JSON 或 BSON 会很简单,因为每行都重复字段名称。这使它在灵活性方面具有优势,但在空间效率方面也有很大的劣势(序列化数据中字段名称的每行开销)。我们试图将内容保存在内存中,并且最小化内存和网络占用空间在这里很重要。我们可以在同一空间中容纳的记录越多,我们的查询就会越快。我们更喜欢相对较长的描述性字段名称,并且缩短它们以使我的数据库更快是错误的!

最后,JSON/BSON 对于我们的目的是行不通的,除非我们变得更复杂,并将小键映射到与数据库对话的应用程序驱动程序中更具描述性的键。这让我们想到...

虽然我们的数据库是无模式的,但实际上:1)没有太多不同种类的实体,2)同种实体的版本不会经常变化,3)当它们发生变化时,通常只是添加另一个领域。JSON/BSON 没有对版本控制的原生支持。

在版本控制和数据定义更改方面,Protocol Buffers 和 Thrift 更加复杂。Thrift 和 Protocol Buffers 都非常适合将数据序列化到数据库中,并且 Thrift 的设计使得编码格式具有可扩展性。

Protocol Buffers 看起来是在无模式数据库中序列化数据的绝佳选择。

CouchDB 和 MongoDB(两个最流行的无模式数据库?)分别使用 JSON 和 BSON,但我们找不到任何关于使用更高级的东西(如 Protocol Buffers)作为存储无模式数据的序列化格式。有些产品可以存储特定语言版本的对象(即,将 Java 的 Externalizable 对象存储在数据网格中,或者在 Ruby 中使用 MySQL 执行 NoSQL),但这些产品很痛苦(尝试从其他平台访问它们,甚至从 MySQL 本身,并忘记版本控制)。

是否有人在他们的数据库中存储了更具互操作性的协议缓冲区,或者在他们的无模式数据库中存储了一些其他高级序列化格式?这是一个问题,除了直接对 JSON/BSON/XML 进行逐行序列化或序列化特定语言的对象之外,是否还有其他选项。它甚至可行吗?我们错过了什么吗?对不起意识流风格的叙述!

4

4 回答 4

3

正如您所发现的,MongoDB 和 CouchDB 对如何存储数据有强烈的看法。如果您正在寻找一种与存储无关的方法,您需要执行@Joshua 建议的操作并查看 Cassandra 或 HBase。甚至这两个数据存储都对如何存储数据(它们都基于Google 的 Bigtable)和将数据存储在列族中存在意见。

Riak使用协议缓冲区作为将数据从应用程序序列化到数据存储区的一种方法。可能值得检查一下它是否符合您的需求。看起来您主要计划进行单键查找,因此 Riak 可能是您解决方案的有力竞争者。

于 2010-11-30T13:01:49.217 回答
1

PostgreSQL 现在有一个 JSON 类型:http ://www.postgresql.org/docs/9.3/static/datatype-json.html

您可以在“触及”这些值的位置进行查询。

将 Protobuf 转换为 JSON 应该很容易。

于 2014-03-06T10:22:40.307 回答
1

您可能想研究 Cassandra 或 HBase 之类的东西来存储您的数据。不透明数据 blob 的问题在于,您无法在此处使用 MySQL 模式基于它进行查询。如果您正在寻找某些东西,则必须阅读每个 blob 并检查它。如果这对于您如何进行查找真的不重要(即您始终是关键),那么我建议使用协议缓冲区来序列化数据,可能使用 zlib 或 LZO 压缩进行压缩。

协议缓冲区允许您创建一个简单的数据结构,该结构可以随着数据的发展接受额外的字段。字段名称存储为数字,使用结构的代码是从您的 .proto 文件中自动生成的。性能很好,数据大小保持很小。您可以选择使用 MySQL compress() 或此处总结的实时压缩库之一(不仅仅是 Java)压缩数据:

Java中的快速压缩?

希望这可以帮助。

于 2010-11-25T02:36:04.650 回答
0

我将向您推荐几个月前我就类似主题提出的答案。我们使用 MySQL 和一种自定义文本格式,它被证明比 XML 或 JSON 格式更快:

您在使用 NoSQL 数据存储时遇到了哪些可扩展性问题?

为我们工作得很好。虽然没有尝试过协议缓冲区。

于 2010-11-30T13:07:04.460 回答