Google应用引擎具有名为后向引用的智能功能,我通常会在需要使用传统SQL计算列的地方进行迭代。
想象一下需要累积特定力量的总hp。
class Force(db.Model):
hp = db.IntegerProperty()
class UnitGroup(db.Model):
force = db.ReferenceProperty(reference_class=Force,collection_name="groups")
hp = db.IntegerProperty()
class Unit(db.Model):
group = db.ReferenceProperty(reference_class=UnitGroup,collection_name="units")
hp = db.IntegerProperty()
当我编写如下代码时,它的速度非常慢(差不多3秒),其中20个力量单组 - 单个单位。 (我想反向引用强制重载子实体。我是对的吗?)
def get_hp(self):
hp = 0
for group in self.groups:
group_hp = 0
for unit in group.units:
group_hp += unit.hp
hp += group_hp
return hp
如何优化此代码?请考虑应为每个force / unit-groups计算更多属性,并且我不想将这些集合属性保存到每个实体。 :)
答案 0 :(得分:2)
Force,UnitGroup和Unit似乎很适合Entity Group。每个Unit属于一个且只有一个UnitGroup并且每个UnitGroup属于一个且只有一个Force,这是真的吗?如果是这样,那么您可以将这些实体存储为实体组,并使用祖先查询来减少数据存储查询的数量。
将实体放入实体组是通过在创建实体时设置其父属性来完成的。完成后,您可以使用单个ancestor query获取属于某个部队的所有单位。
话虽如此,正确的做法是在将实体写入数据库时计算值,而不是在读取它们时。这个和其他地方一遍又一遍地注意到这个简单的事实,它是从AppEngine应用程序中获得良好性能的最佳方式。它可能看起来像预先做了很多工作,对于那些拥有传统SQL数据库背景的人来说,这是非常反直觉的,但这是你想要做的,简单明了。
答案 1 :(得分:2)
App Engine上的存储成本很低,而CPU和请求时间则较少。关于数据存储区,你应该记住的主要事情是你应该优化读取而不是写入 - 你最终会比编写数据更频繁地读取数据。
如果您认为自己可能需要知道Force
的总hp
,则应将其存储在名为total_hp
的字段中,并每次使用新值更新您更新/添加/删除其UnitGroup
和Unit
。您也应该在事务中执行此操作,这意味着它们需要位于同一个实体组中。