有没有与Google Datastore或BigTable合作过的人有任何可以给出的建议?
与“传统”的关系型数据库相比,App Engine数据存储有两个主要的需要适应的方面:
要了解的重要事情 - 以及这些差异背后的原因 - 是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()
我来自关系型数据库世界,然后发现了这个Datastore。花了几天时间才摸清楚它的用法。好吧,以下是我的发现。
你一定已经知道Datastore是为了扩展而构建的,这是它与关系型数据库不同之处。为了更好地处理大型数据集,App Engine进行了一些更改(有些意味着很多更改)。
关系型数据库 VS DataStore
结构
在数据库中,我们通常将数据结构化为表格、行,在Datastore中则变成了Kinds和Entities。
关系
在关系型数据库中,大多数人都遵循一对一、多对一、多对多的关系。在Datastore中,虽然没有"Join"的概念,但我们仍然可以使用"ReferenceProperty"来实现规范化,例如一对一关系示例。
索引
通常在关系型数据库中,我们会创建主键、外键、唯一键和索引键等索引来加快搜索速度和提高数据库性能。而在数据存储中,您必须至少为每个种类创建一个索引(无论您是否喜欢,它都会自动生成),因为数据存储根据这些索引搜索实体,相信我,这是最好的部分。在关系型数据库中,您可以使用非索引字段进行搜索,尽管需要一些时间,但是可以。在数据存储中,您不能使用非索引属性进行搜索。
计数
在关系型数据库中,使用count(*)更容易,但在数据存储中,请不要以常规方式思考(是的,有一个count函数),因为它有1000限制,并且会像实体一样产生小操作的成本,这不好,但我们总有好的选择,我们可以使用分片计数器。
唯一约束
在关系型数据库中,我们喜欢这个功能,对吧?但是数据存储有自己的方式。你不能定义一个属性为唯一的:(。
查询
GAE Datastore提供了更好的功能,类似于SQL中的LIKE(哦不!Datastore没有LIKE关键字),即GQL。
数据插入/更新/删除/选择
这是我们所有人都感兴趣的地方,就像在关系型数据库中一样,我们需要一个查询来进行插入、更新、删除和选择,Datastore也有put、delete、get(不要太激动),因为Datastore使用写入、读取、小操作(阅读 Datastore调用成本)来表示put或get,这就是数据建模发挥作用的地方。您必须最小化这些操作并保持应用程序运行。为了减少读操作,您可以使用Memcache。
如果你已经习惯了思考ORM映射实体,那么像谷歌应用引擎这样的基于实体的数据存储就是这样工作的。对于类似连接的操作,可以查看引用属性。你不需要关心它是否使用BigTable作为后端或其他什么东西,因为后端由GQL和Datastore API接口抽象。
作为一个根植于数据库世界的人,对我来说,数据存储就像是一个巨大的表格(因此得名“bigtable”)。但BigTable并不是一个好的例子,因为它做了很多其他典型数据库可能不会做的事情,但它仍然是一个数据库。除非你知道自己需要构建类似Google的“bigtable”,否则使用标准数据库应该已经足够了。他们需要这样做是因为他们正在处理大量的数据和系统,并且没有任何商业可用的系统可以真正按照他们所需的方式完成工作。
(bigtable参考:http://en.wikipedia.org/wiki/BigTable)