【问题标题】:Why, or why not, to use a schema free database?为什么或为什么不使用无模式数据库?
【发布时间】:2013-05-01 07:24:16
【问题描述】:

我已经尝试在 Web 应用程序中仅使用 mongodb 有一段时间了。但我想知道为什么有些人说无模式或动态模式很强大。现在我不认为它如此美妙或美妙。有人想谈谈使用无模式数据库的正确案例吗?首先我想讲一些我的故事。

什么是无模式、数据库或代码?

大多数 NoSQL 数据库都想说它们是无模式的,但我认为重要的部分是在应用程序中运行的代码。

例如,用户信息的存储可以是无模式的,但这并不意味着您可以将用户名存储为对象或将密码存储为时间戳。用户登录代码假定用户名是字符串,密码是哈希值。最终,数据库存储受限于模式。

嵌入式文档难以维护或查询

我创建了一个 CMS 作为示例来开始我的 NoSQL 数据库生活。一开始posts和cmets数据是这样存储的

[
{
    title: 'Mongo is Good',
    content: 'Mongo is a NoSQL database.',
    tags: ['Database', 'MongoDB', 'NoSQL'],
    comments: [ COMMENT_0, COMMENT_1, ... ]
},
{
    title: 'Design CMS',
    content: 'Design a blog or something else.',
    tags: ['Web', 'CMS'],
    comments: [ COMMENT_2, COMMENT_3, ... ]
},
...
]

如您所见,我将 cmets 嵌入到每个帖子的列表中。这非常方便,因为我可以轻松地将新评论附加到任何帖子或随帖子一起检索 cmets。但是很快我就遇到了第一个问题:从列表中删除某个评论(通常是垃圾邮件)非常麻烦。令我惊讶的是 mongo haven't still implemented it

除了 API 级别的问题之外,还很难跨集合查询嵌入的文档。如果我坚持这种设计,以下查询只能以暴力方式实现

  • 最近的cmets
  • 某个用户的cmets

最终我不得不将 cmets 放入另一个集合中,使用 post_id 字段存储评论所属帖子的 id,就像我们在关系数据库中所做的 FK 一样。

尽管采用 cmets 设计,但帖子标签还是很有帮助的。

我在this post找到了意见

在 NoSQL 中,您不会根据数据实体之间的关系来设计数据库。您可以根据将针对它运行的查询来设计数据库。

但是需求的变化呢?仅仅因为应该支持一个新的查询就重构一个数据库是不是太疯狂了?

这些案例值得无架构

在其他一些需要无架构存储的情况下。例如,类似推特的时间线,数据格式如下

[
{
    _id: ObjectId('aaa'),
    type: 'tweet',
    user: ObjectId('xxx'),
    content: '0000',
},
{
    _id: ObjectId('bbb'),
    type: 'retweet',
    user: ObjectId('yyy'),
    ref: ObjectId('aaa'),
},
...
]

问题在于将文档呈现为 HTML 并不是一件容易的事。我以这种方式渲染它们(Python)

renderMethods = {
    'tweet': render_tweet,
    'retweet': render_retweet,
}
result = [ render_methods[u['type']](u) for u in updates ]

因为只存储 JSON 数据,而不是成员函数。结果,我必须根据其类型手动将渲染函数映射到每个更新。 (当服务器通过 AJAX 将 JSON 完整发送到浏览器时也会发生类似的事情)

上面的问题让我很困惑。有没有人想谈谈无模式数据库的良好实践,以及在单个应用程序中混合一个关系数据库和无模式数据库是否是一个好的决定?

【问题讨论】:

  • 您的帖子读起来更像是对 mongodb 无模式概念的咆哮,而不是一个问题。我只是没有反对它,因为它是一个格式正确且语法正确的咆哮:)

标签: database nosql schema schema-design


【解决方案1】:

在具有继承的面向对象的上下文中使用无模式数据库时,它们的主要优势就显现出来了。

继承意味着你的对象有一些共同的属性,但也有一些特定于对象子类型的属性。

想象一下,例如,计算机硬件商店的产品目录。

每个产品都将具有namevendorprice 属性。但是 CPU 会有一个clock_rate,硬盘驱动器会有一个capacity,RAM 有capacityclock_rate,网卡有一个bandwidth。在关系数据库中执行此操作会留下两个同样麻烦的选项:

  1. 为所有可能的属性创建一个包含字段的表,但对于不适用的产品,将大部分属性保留为 NULL。
  2. 使用productIdattribute_nameattribute_value 创建一个辅助表“product_attributes”。

另一方面,无模式数据库可以轻松地将具有不同可选属性集的项目存储在同一个集合中。将产品属性呈现为 HTML 的代码将检查每个已知的可选属性是否存在,然后调用适当的函数,将其值输出为表格行。

无模式数据库的另一个优点是它在开发过程中提供了额外的敏捷性。它可以让您轻松尝试新功能,而无需重新构建数据库。这使得维护与应用程序先前版本创建的数据的向后兼容性变得非常容易,而无需运行复杂的数据库转换例程。我目前正在使用 MongoDB 开发 MMORPG。在开发过程中,我添加了许多新功能,这些新功能需要将每个字符的新数据保存在数据库中。我从来不需要在我的数据库上运行一个等同于 CREATE TABLE 或 ALTER TABLE 的命令。 MongoDB 只是吃掉了我扔给它的任何数据。我的第一个测试角色仍然可以玩,尽管我从未有意升级到它的数据库文档。它有一些过时的字段,这些字段是我丢弃或重构的功能的残余,但这些并没有什么坏处——这些过时的字段会很有用,尽管当我的玩家尖叫着要恢复我删除的功能时。

【讨论】:

  • 有趣。我认为游戏开发与网络开发完全不同。它需要在 Web 应用程序中跨整个数据库的各种查询和统计信息。也许正因为如此,关系数据库似乎更合适。
  • @neutront 查询和统计数据对于游戏开发也很重要——它们可用于获取有关玩家行为的有价值信息,这对平衡很重要。如果您有 200 种不同的武器,并且查询显示总游戏时间超过 50 小时的所有玩家中有 99% 使用相同的武器,那就是有问题。
【解决方案2】:

在关系数据库中执行此操作会留下两个同样麻烦的选项:

我猜这里还有一个选项。 以 xml 格式添加数据,并让应用程序按照它想要的方式对其进行反序列化/序列化。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-04
    • 1970-01-01
    • 1970-01-01
    • 2012-05-15
    • 2011-01-28
    • 2016-12-04
    • 1970-01-01
    相关资源
    最近更新 更多