我们正在使用 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 ;
一些细节:
存储实体唯一需要的属性是
id
16 字节的 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 进行逐行序列化或序列化特定语言的对象之外,是否还有其他选项。它甚至可行吗?我们错过了什么吗?对不起意识流风格的叙述!