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


183

举例来说,Google App Engine使用Google数据存储区(而不是标准数据库)来存储数据。是否有人有使用Google数据存储区而不是数据库的提示?看来我已经训练好自己的思维,以100%地考虑直接映射到表结构的对象关系,现在很难看到任何不同的东西。我可以理解Google数据存储区的一些好处(例如性能和分发数据的能力),但是却牺牲了一些良好的数据库功能(例如联接)。

使用Google数据存储区或BigTable的人有与他们合作的任何好的建议吗?


DataSource是一个旧的api,我们正在逐渐删除它-它与数据库连接模型非常相关。DataStore是低级api,它允许使用FeatureReaders和FeatureWriter访问基于“原始”流的GIS内容方法。
murali

现在,Google Cloud SQL为Google App Engine提供了关系数据库支持。如果您仍在寻找数据存储解决方案,则可以使用Google Cloud SQL
昌达纳2012年

您可能想查看Mungo数据存储区API:bit.ly/13eSDpr
夸克

Answers:


149

与“传统”关系数据库相比,需要熟悉App Engine数据存储的两件事:

  • 数据存储区在插入和更新之间没有区别。当您在实体上调用put()时,该实体将使用其唯一键存储到数据存储中,所有具有该键的内容都将被覆盖。基本上,数据存储区中的每种实体类型都像一个巨大的地图或排序列表。
  • 正如您所提到的,查询的局限性更大。首先不要加入。

要实现的关键点以及这两种差异背后的原因是,Bigtable基本上就像一个巨大的有序字典。因此,放置操作仅设置给定密钥的值,而不管该密钥的任何先前值,并且提取操作仅限于提取单个密钥或连续范围的密钥。索引使更复杂的查询成为可能,这些索引基本上只是它们自己的表,使您可以将更复杂的查询实现为对连续范围的扫描。

一旦了解了这一点,便拥有了了解数据存储的功能和局限性所需的基本知识。似乎是任意的限制可能更有意义。

这里的关键是,尽管这些是对您在关系数据库中可以执行的操作的限制,但是这些相同的限制使得切实可行地扩展到Bigtable旨在处理的规模。您根本无法执行在表面上看起来不错但在SQL数据库中非常慢的查询。

在如何更改数据表示方式方面,最重要的是预先计算。与其在查询时进行联接,不如预先计算数据并将其存储在数据存储中。如果要选择随机记录,请生成一个随机数并将其与每个记录一起存储。有这些种类的技巧和窍门的整个食谱这里编辑:菜谱是不再存在。


4
好消息,互联网没有忘记食谱,即互联网档案没有忘记。该网站的幽灵仍然存在于此:web.archive.org/web/20090416113704/http
//…

42

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

在关系数据库世界中,您始终必须担心数据规范化和表结构。抛弃一切。只需布置您的网页即可。布置它们全部。现在看看他们。你已经在那里2/3了。

如果您忘记了数据库大小很重要且不应重复数据的想法,那么您的位置就是3/4,您甚至不必编写任何代码!让您的意见决定您的模型。您不必像在关系世界中那样将物体变成二维物体。您现在可以存储具有形状的对象。

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


2
我喜欢“让您的意见决定您的模型”。一点。我认为这是RDBMS的挂断,但是它简化了所有事情。
cbednarski

23

当人们出来时,我总是笑着说-这与关系无关。我用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()    

12

我来自关系数据库世界,然后我发现了这个数据存储库。花了几天时间才摆脱困境。好吧,我有一些发现。

您必须已经知道Datastore是按比例构建的,这就是将其与RDMBS分开的原因。为了更好地处理大型数据集,App Engine进行了一些更改(某些更改意味着很多更改)。

RDBMS VS 数据存储
结构
在数据库中,我们通常将数据结构化为表,行,这些数据在数据存储中变为Kinds和Entities

关系
在RDBMS中,大多数人的folllows一到一,多到一,多对一一对多的关系,在数据存储中,因为它没有“联接”的事情,但我们仍然可以用“实现我们的标准化的ReferenceProperty “例如一对一关系的例子

索引
通常,在RDMBS中,我们进行主键,外键,唯一键和索引键之类的索引,以加快搜索速度并提高数据库性能。在数据存储区中,您必须为每种索引至少创建一个索引(它将自动生成您是否喜欢),因为数据存储区会根据这些索引搜索您的实体,并认为这是最好的部分,在RDBMS中,您可以使用非索引字段虽然会花费一些时间,但是会。在数据存储区中,您无法使用非索引属性进行搜索。

计数
在RDMBS中,计数(*)要容易得多,但在数据存储区中,请不要以正常方式考虑(是的,有一个计数函数),因为它有1000个Limit,并且将花费与实体一样小的操作量不好,但是我们总是有很好的选择,我们可以使用碎片计数器

独特的限制
在RDMBS中,我们喜欢此功能,对吗?但是数据存储区有其自己的方式。您不能将属性定义为唯一的:(。

查询
GAE Datatore提供了更好的功能太多LIKE(哦,不!数据存储没有LIKE关键字),SQL是GQL

数据插入/更新/删除/选择
这是我们所有人都感兴趣的地方,就像在RDMBS中一样,我们需要对插入,更新,删除和选择进行一次查询,就像RDBMS一样,数据存储区放置,删除,获取(不要太兴奋),因为数据存储区根据写入,读取,小型操作数据存储调用的读取成本)放置或获取数据,这就是数据建模开始起作用的地方。您必须最小化这些操作并保持应用程序运行。对于减少读取操作,可以使用Memcache



3

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


1
引用属性的一个问题是它们可以快速创建1 + N查询问题。(拉1个查询以查找100个人,然后对每个人进行另一个查询以获取
person.address

链接到“引用属性”的链接可能已损坏,可能是由于添加了Java支持。尝试:code.google.com/appengine/docs/python/datastore/...
Spike0xff

链接固定。如果/当您有足够的代表时,可以随时编辑任何答案。
Mark Cidade

0

我看数据存储的方式是,种类本身就是表,而实体是表中的单独行。如果Google要拿出比其只有一个没有结构的大表好,那么您可以将所需的内容转储到一个实体中。换句话说,如果实体不绑定到一种实体,则您几乎可以对实体具有任何结构,并将其存储在一个位置(有点大的文件,没有结构,每行都有其自己的结构)。

现在回到原始注释,google数据存储区和bigtable是两个不同的东西,因此不要混淆google数据存储区到datastore数据存储的意义。Bigtable比bigquery昂贵(主要原因是我们没有使用它)。Bigquery确实具有适当的连接和RDBMS(例如sql语言),并且价格便宜,为什么不使用bigquery。话虽如此,bigquery确实有一些限制,具体取决于您可能会遇到或可能不会遇到的数据大小。

此外,就数据存储而言,我认为正确的陈述应该是“就NoSQL数据库而言”。这些天有太多可用的方法,但是当涉及到Google产品(除Google Cloud SQL(即mySQL)以外)时,其他一切都是NoSQL。


-6

根植于数据库世界,对我而言,数据存储将是一个巨大的表(因此名称为“ bigtable”)。BigTable是一个不好的例子,因为它做了很多其他的事情,而典型的数据库可能做不到,但它仍然是数据库。除非您知道需要构建类似Google的“ bigtable”之类的东西,否则使用标准数据库可能会很好。他们之所以需要这样做,是因为他们正在一起处理大量的数据和系统,并且没有任何商业上可用的系统能够真正以证明他们需要完成工作的确切方式来完成这项工作。

(bigtable参考:http : //en.wikipedia.org/wiki/BigTable


这个问题专门与使用Bigtable的Google App Engine有关;使用关系数据库不是一种选择。
尼克·约翰逊
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.