【问题标题】:Relational vs Non-Relational Data Modeling - what's the difference关系与非关系数据建模 - 有什么区别
【发布时间】:2011-08-25 02:33:06
【问题描述】:

我是数据库新手,从未使用过任何 RDBMS。但是我得到了关系数据库的基本概念。至少我认为我这样做;-)

假设我有一个用户数据库,每个用户都有以下属性:

  • 用户
    • 身份证
    • 姓名
    • 压缩包
    • 城市

在关系数据库中,例如,我会在名为user的表中对其进行建模

  • 用户
    • 身份证
    • 姓名
    • location_id

并有第二个表名为location

  • 位置
    • 身份证
    • 压缩包
    • 城市

而location_id 是location 表中条目的外键(引用)。如果我理解正确,优势就在这里,如果某个城市的邮政编码发生变化,我只需更改一个条目。

那么,让我们转到非关系型数据库,在那里我开始使用 Google App Engine。在这里,我真的会对其进行建模,就像它首先写在规范中一样。我有种user:

class User(db.Model):
    name = db.StringProperty()
    zip = db.StringProperty()
    city = db.StringProperty()

优点是我不需要加入两个“表格”,但缺点是,如果邮政编码发生变化,我必须运行一个脚本来遍历所有用户条目并更新邮政编码,对吗?

所以,现在 Google App Engine 中还有另一个选项,那就是使用 ReferenceProperties。我可以有两种:user 和 location

class Location(db.Model):
    zip = db.StringProperty()
    city = db.StringProperty()

class User(db.Model):
    name = db.StringProperty()
    location = db.ReferenceProperty(Location)

如果我没记错的话,我现在的模型与上述关系数据库中的模型完全相同。我现在想知道的是,首先,我刚才所做的和所做的是否是错误的,它破坏了非关系数据库的所有优势。我知道,为了获得 zip 和 city 的值,我必须运行第二个查询。但在另一种情况下,要更改邮政编码,我必须遍历所有现有用户。

那么在像 Google 的数据存储这样的非关系型数据库中,这两种建模可能性的含义是什么。以及它们的典型用例是什么,这意味着我应该什么时候使用一个,什么时候使用另一个。

另外一个问题是,如果在非关系数据库中我可以建模与在关系数据库中建模的完全相同,我为什么要使用关系数据库?

很抱歉,如果其中一些问题听起来很幼稚,但我相信它们会帮助一些刚接触数据库系统的人更好地理解。

【问题讨论】:

    标签: google-app-engine data-modeling relational-database non-relational-database


    【解决方案1】:

    根据我的经验,最大的不同是非关系型数据存储迫使您根据查询方式进行建模,因为缺少连接,并且由于事务限制,您将如何编写。这当然会导致非常非规范化的模型。过了一会儿,我开始首先定义所有查询,以避免以后重新考虑模型。

    由于关系数据库的灵活性,您可以单独考虑每个数据族,在它们之间创建关系并最终查询您希望的方式(在很多情况下滥用连接)。

    【讨论】:

    • +1 好答案。现在回想起来,不知不觉我也在做同样的事情。
    • 这正是我要写的。 :)
    【解决方案2】:

    假设 GAE 有两种数据存储模式:RDMS 模式和非 RDMS 模式。 如果我以“列出所有用户及其所有邮政编码”为目标以您的 ReferenceProperty 示例为例,并编写一些代码来打印所有这些。

    对于 [虚构的] RDMS 模式数据存储,它可能如下所示:

    for user in User.all().join("location"):
        print("name: %s zip: %s" % (user.name, user.location.zip))
    

    我们的 RDMS 系统已经处理了语义背后的数据的反规范化,并且在一次查询中返回了我们需要的所有数据方面做得很好。这个查询确实有一点点开销,因为它必须将我们的两个表拼接在一起。

    对于非 RDMS 数据存储,我们的代码可能如下所示:

    for user in User.all():
        location = Location.get( user.location )†
        print("name: %s zip: %s" % (user.name, location.zip))
    

    在这里,Datastore 无法帮助我们加入数据,我们必须对每个 user 实体进行额外查询以获取 location,然后才能打印它。

    这实质上就是您要避免在非 RDMS 系统上过度规范化数据的原因。

    现在,无论他们是否使用 RDMS,每个人都在某种程度上对他们的数据进行了逻辑规范化,诀窍是为您的用例找到便利性和性能之间的权衡。

    † 这不是有效的 appengine 代码,我只是说明user.location 会触发数据库查询。也没有人应该像我上面的极端示例那样编写代码,您可以通过预先批量获取位置来解决持续获取相关实体的问题。

    如果我可以在非关系数据库中建模与在关系数据库中建模的完全相同,我为什么要使用关系数据库?

    relational-DB 擅长存储成千上万行复杂的相互关联的数据模型,并允许您执行极其复杂的查询来重构和访问这些数据。

    非 RDB 擅长存储数十亿行以上的简单数据,并允许您通过更简单的查询来获取这些数据。

    真正的选择应该取决于您的用例。非关系模型的更简单结构和随之而来的设计限制是 AppEngine 能够承诺根据需求扩展您的应用的主要方式之一。

    【讨论】:

      【解决方案3】:

      您对关系数据库概念的理解存在缺陷。关系数据库在包含一组相同类型的元组的关系中组织它们的数据。换句话说,数据存储在表中,每行包含相同数量的相同类型的字段,顺序相同。

      您提供的使用外键的示例演示了database normalization。这是一个适用于关系数据库以及其他类型数据库的概念。

      很抱歉,我无法回答您有关 Google 存储系统的问题,但希望这足以阐明您的理解,以便找出答案。

      【讨论】:

        猜你喜欢
        • 2010-10-20
        • 2015-01-31
        • 2014-07-13
        • 1970-01-01
        • 2014-01-13
        • 2014-03-27
        • 2011-10-24
        • 2015-12-18
        • 1970-01-01
        相关资源
        最近更新 更多