如何在数据存储而不是数据库中思考?

例如,GoogleAppEngine 使用 GoogleDatastore 而不是标准数据库来存储数据。有人有使用谷歌数据存储而不是数据库的建议吗?似乎我已经训练自己的大脑在直接映射到表结构的对象关系中100% 地进行思考,现在很难看出有什么不同了。我可以理解 Google Datastore 的一些好处(例如性能和分发数据的能力) ,但是牺牲了一些好的数据库功能(例如连接)。

任何曾经使用过 Google Datastore 或 BigTable 的人对于如何使用它们有什么好的建议吗?

24043 次浏览

由于植根于数据库世界,数据存储对我来说就是一个巨大的表(因此得名“ bigtable”)。但 BigTable 是一个糟糕的例子,因为它做了许多典型数据库可能不会做的事情,但它仍然是一个数据库。除非你知道你需要构建一个像 Google 的“ bigtable”这样的东西,否则使用标准的数据库很可能没问题。他们需要这样做,因为他们一起处理大量的数据和系统,没有任何商业可用的系统可以真正做到这一点,他们可以证明,他们需要这项工作要做的确切方式。

(大表参考: http://en.wikipedia.org/wiki/BigTable)

我一直在进行思维转换的方法就是完全忘记数据库。

在关系数据库世界中,您总是不得不担心数据规范化和表结构。全部扔掉。只是布局你的网页。把它们都摆出来。现在看看他们。你已经有三分之二了。

如果你忘记了数据库大小的重要性和数据不应该被复制的概念,那么你就是3/4,你甚至不需要编写任何代码!让您的视图支配您的模型。你不必再像在关系世界中那样把你的对象变成二维的。您现在可以存储具有形状的对象。

是的,这是对这一考验的简化解释,但它帮助我忘记了数据库,只是制作了一个应用程序。到目前为止,我已经使用这个理念开发了4个 App Engine 应用程序,还会有更多的应用程序。

如果您习惯于考虑 ORM 映射的实体,那么这基本上就是基于实体的数据存储(如 Google 的 App Engine)的工作方式。对于连接之类的东西,可以查看 参考属性。您实际上不需要关心它是否使用 BigTable 作为后端或其他东西,因为后端是由 GQL 和 Datastore API 接口抽象的。

与“传统的”关系数据库相比,App Engine 数据存储主要有两点需要习惯:

  • 数据存储不区分插入和更新。当您对一个实体调用 put ()时,该实体将使用其唯一键存储到数据存储中,并且任何具有该键的内容都将被覆盖。基本上,数据存储中的每种实体都像一个巨大的映射或排序列表。
  • 正如您提到的那样,查询受到的限制要多得多。

需要认识到的关键问题——以及这两种差异背后的原因——是 Bigtable 基本上就像一个庞大的有序字典。因此,put 操作只设置给定键的值——不管该键之前的值是什么,并且提取操作仅限于提取单个键或连续范围的键。使用索引可以实现更复杂的查询,索引基本上只是它们自己的表,允许您将更复杂的查询实现为连续范围上的扫描。

一旦理解了这一点,您就掌握了理解数据存储的功能和局限性所需的基本知识。那些看似随意的限制可能更有意义。

这里的关键问题是,尽管这些限制限制了你在一个关系数据库中可以做什么,但是同样的限制使得扩展到 Bigtable 设计用来处理的那种大小变得可行。您不能简单地执行这种查询,它在纸上看起来很好,但在 SQL 数据库中却非常慢。

关于如何更改表示数据的方式,最重要的是预计算。不要在查询时执行连接,而是预先计算数据并尽可能将其存储在数据存储中。如果要选择一条随机记录,请生成一个随机数并与每条记录一起存储。有一整本关于这种技巧和窍门的烹饪书。

当人们说出来的时候,我总是咯咯地笑——这不是关系。我用 django 编写了 cellectr,下面是我的模型的一个片段。正如您将看到的,我有一些由用户管理或指导的联盟。我可以从一个联盟得到所有的经理,或者从一个给定的用户,我可以返回的联盟,她的教练或经理。

仅仅因为没有特定的外键支持并不意味着您不能拥有具有关系的数据库模型。

我的两便士。


class League(BaseModel):
name = db.StringProperty()
managers = db.ListProperty(db.Key) #all the users who can view/edit this league
coaches = db.ListProperty(db.Key) #all the users who are able to view this league


def get_managers(self):
# This returns the models themselves, not just the keys that are stored in teams
return UserPrefs.get(self.managers)


def get_coaches(self):
# This returns the models themselves, not just the keys that are stored in teams
return UserPrefs.get(self.coaches)


def __str__(self):
return self.name


# Need to delete all the associated games, teams and players
def delete(self):
for player in self.leagues_players:
player.delete()
for game in self.leagues_games:
game.delete()
for team in self.leagues_teams:
team.delete()
super(League, self).delete()


class UserPrefs(db.Model):
user = db.UserProperty()
league_ref = db.ReferenceProperty(reference_class=League,
collection_name='users') #league the users are managing


def __str__(self):
return self.user.nickname


# many-to-many relationship, a user can coach many leagues, a league can be
# coached by many users
@property
def managing(self):
return League.gql('WHERE managers = :1', self.key())


@property
def coaching(self):
return League.gql('WHERE coaches = :1', self.key())


# remove all references to me when I'm deleted
def delete(self):
for manager in self.managing:
manager.managers.remove(self.key())
manager.put()
for coach in self.managing:
coach.coaches.remove(self.key())
coaches.put()
super(UserPrefs, self).delete()

看一下 Objectify 文档,页面底部的第一条评论说:

“很好,虽然你写这篇文章是为了描述 Objectify,但它也是我读过的关于 appengine 数据存储本身的最简明的解释之一。谢谢

Https://github.com/objectify/objectify/wiki/concepts

我来自关系数据库然后我发现了这个 Datastore 的东西。我花了好几天才掌握它。我有一些发现。

您必须已经知道 Datastore 是按比例构建的,这就是它与 RDMBS 的区别。为了更好地扩展大型数据集,AppEngine 做了一些更改(有些更改意味着大量更改)。

关系数据库 VS 数据存储
结构
在数据库中,我们通常将数据结构放在表格、行中,在 Datastore,它变成了 种类及实体

关系
在 RDBMS,大多数人遵循一对一,多对一,多对多的关系,在 Datastore,因为它有“无连接”的东西,但我们仍然可以实现我们的正常化使用“ 参考属性”,例如 一对一关系示例

索引
通常在 RDMBS 中,我们创建主键、外键、唯一键和索引键等索引,以加快搜索速度,提高数据库性能。在数据存储中,你必须为每一种类型至少创建一个索引(不管你喜欢与否,它都会自动为 产生) ,因为数据存储基于这些索引来搜索你的实体,相信我,这是最好的部分。在 RDBMS 中,你可以使用非索引字段来搜索,虽然这会花费一些时间,但它会的。在 Datastore 中,不能使用非索引属性进行搜索。

数数
在 RDMBS,计数(*)要容易得多,但是在 datastore 中,请不要以正常的方式去想它(是的,有一个 count 函数) ,因为它有 1000上限,它将花费和实体一样多的 小型行动,这不是很好,但是我们总是有很好的选择,我们可以使用 碎片计数器

唯一约束
在 RDMBS,我们喜欢这个功能,对吗?但是 Datastore 有它自己的方式。不能将属性定义为惟一的: (。

质疑
GAE Datatore 提供了一个更好的特性很多 喜欢(哦,不! datastore 没有象关键字) SQL,这是 GQL

数据插入/更新/删除/选择
这是我们都感兴趣的地方,因为在 RDMBS 中,我们需要一个关于插入、更新、删除和选择的查询,就像 RDBMS 一样,Datastore 已经放入、删除、获取(不要太兴奋) ,因为 Datastore 放入或获取的术语是 写,读,小操作(阅读 数据存储调用的成本) ,这就是数据建模开始行动的地方。你必须最小化这些操作,并保持你的应用程序运行。为了减少 读操作,你可以使用 Memcache

我查看数据存储的方式是,kind 标识表,本质上,实体是表中的单个行。如果谷歌删除了一种比它只是一个没有结构的大表,你可以转储在一个实体中你想要的任何东西。换句话说,如果实体没有绑定到某种类型,那么你几乎可以将任何结构绑定到某个实体并存储在一个位置(类似于没有结构的大型文件,每一行都有自己的结构)。

现在回到最初的评论,google datastore 和 bigtable 是两个不同的东西,所以不要混淆 google datastore 和 datastore 的数据存储意义。Bigtable 比 bigquery 更昂贵(主要原因是我们没有使用它)。Bigquery 确实有像 sql 语言一样的适当的连接和 RDBMS,而且成本更低,为什么不使用 Bigquery 呢。也就是说,bigquery 确实有一些限制,这取决于您可能会遇到或可能不会遇到的数据的大小。

另外,从数据存储的角度考虑,我认为正确的语句应该是“从 NoSQL 数据库的角度考虑”。现在有太多这样的产品可供选择,但是当涉及到谷歌产品时,除了谷歌云 SQL (也就是 mySQL) ,其他的都是 NoSQL。