Google app engine 关系型与非关系型数据建模-什么';有什么区别
我是数据库新手,从未使用过任何RDBMS。不过,我了解了关系数据库的基本概念。至少我想我知道;-) 假设我有一个用户数据库,每个用户都有以下属性:Google app engine 关系型与非关系型数据建模-什么';有什么区别,google-app-engine,data-modeling,relational-database,non-relational-database,Google App Engine,Data Modeling,Relational Database,Non Relational Database,我是数据库新手,从未使用过任何RDBMS。不过,我了解了关系数据库的基本概念。至少我想我知道;-) 假设我有一个用户数据库,每个用户都有以下属性: 使用者 身份证 名字 拉链 城市 例如,在关系数据库中,我将在名为user的表中对其进行建模 使用者 身份证 名字 位置标识 还有第二个表名为location class Location(db.Model): zip = db.StringProperty() city = db.StringProperty()
- 使用者
- 身份证
- 名字
- 拉链
- 城市
user的表中对其进行建模
- 使用者
- 身份证
- 名字
- 位置标识
还有第二个表名为location
class Location(db.Model):
zip = db.StringProperty()
city = db.StringProperty()
class User(db.Model):
name = db.StringProperty()
location = db.ReferenceProperty(Location)
- 位置
- 身份证
- 拉链
- 城市
而location\u id
是指向location
表中条目的外键(引用)。如果我理解正确,优势就在这里,如果某个城市的邮政编码发生变化,我只需更改一个条目
那么,让我们转到非关系数据库,在那里我开始使用Google App Engine。在这里,我真的会对它进行建模,就像在规范中首先写下一样。我有一个善良的用户
:
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的值,我必须运行第二个查询。但在另一种情况下,要更改邮政编码,我必须遍历所有现有用户
那么,在非关系型数据库(如谷歌的数据存储)中,这两种建模可能性意味着什么呢。它们的典型用例是什么,也就是说,我应该在什么时候使用一个,什么时候使用另一个
另外一个问题是,如果在一个非关系型数据库中,我可以建立与在关系型数据库中完全相同的模型,那么我为什么要使用关系型数据库呢
很抱歉,如果这些问题听起来很幼稚,但我相信它们会帮助一些刚刚接触数据库系统的人更好地理解关系数据库的概念。您对关系数据库概念的理解是有缺陷的。关系数据库在包含一组相同类型元组的关系中组织数据。换言之,数据存储在表中,每行包含相同数量、相同类型、相同顺序的字段
您提供的使用外键的示例演示了。这是一个可以应用于关系数据库以及其他类型数据库的概念
很抱歉,我无法回答您关于谷歌存储系统的问题,但希望这能充分澄清您的理解,让您找到答案。根据我的经验,最大的区别在于非关系型数据存储迫使您基于查询方式建模,因为缺少连接和编写方式,因为交易限制。这当然会导致非常非规范化的模型。过了一会儿,我开始先定义所有的查询,以避免以后重新考虑模型
由于关系数据库的灵活性,您可以单独考虑每个数据族,在它们之间创建关系,并最终查询您希望的方式(在许多情况下滥用连接)。想象GAE有两种数据存储模式:RDMS模式和非RDMS模式。
如果我以您的ReferenceProperty为例,目标是“列出所有用户及其邮政编码”,并编写一些代码来打印所有这些内容
对于[虚构的]RDMS模式数据存储,它可能看起来像:
for user in User.all().join("location"):
print("name: %s zip: %s" % (user.name, user.location.zip))
for user in User.all():
location = Location.get( user.location )†
print("name: %s zip: %s" % (user.name, location.zip))
我们的RDMS系统已经处理了SENSE背后数据的非标准化,并且在一次查询中返回了我们需要的所有数据,这项工作做得很好。这个查询确实有一点开销,因为它必须将两个表缝合在一起
对于非RDMS数据存储,我们的代码可能如下所示:
for user in User.all().join("location"):
print("name: %s zip: %s" % (user.name, user.location.zip))
for user in User.all():
location = Location.get( user.location )†
print("name: %s zip: %s" % (user.name, location.zip))
在这里,数据存储无法帮助我们加入数据,我们必须对每个用户
实体进行额外查询,以获取位置
,然后才能打印它
这就是您希望避免在非RDMS系统上过度规范化数据的本质原因
现在,无论是否使用RDM,每个人都会在一定程度上对其数据进行逻辑规范化,关键在于为您的用例找到方便性和性能之间的权衡
†这不是有效的appengine代码,我只是说明user.location
会触发db查询。同样,没有人应该像我上面的极端示例那样编写代码,您可以通过预先批量获取位置来解决相关实体的持续获取问题
如果在非关系数据库中,我可以建立与在关系数据库中完全相同的模型,那么我为什么要使用关系数据库呢
relational DB的excel能够存储成千上万行复杂的相互关联的数据模型,并允许您执行极其复杂的查询来修改和访问这些数据
非RDB的excel能够存储数十亿行以上的简单数据,并允许您通过更简单的查询获取这些数据
选择应该取决于您的用例。非关系模型的简单结构和随之而来的设计限制是AppEngine能够承诺根据需求扩展应用程序的主要方式之一。+1