下面的代码是作为cronjob定期运行的,而且计算成本非常高!主要的问题是for循环,我认为使用更好的过滤可以提高效率,但我不知道如何做到这一点。
free_membership_type = MembershipType.all().filter("membership_class =", "Free").filter("live =", True).get()
all_free_users = UserMembershipType.all().filter("membership_active =", True)
all_free_users = all_free_users.filter("membership_type =", free_membership_type).fetch(limit = 999999)
if all_free_users:
for free_user in all_free_users:
activation_status = ActivationStatus.all().filter("user = ", free_user.user).get()
if activation_status and activation_status.activated:
documents_left = WeeklyLimits.all().filter("user = ", free_user.user).get()
if documents_left > 0:
do something...
代码使用的模型有:
class MembershipType(db.Model):
membership_class = db.StringProperty()
membership_code = db.StringProperty()
live = db.BooleanProperty(default = False)
class UserMembershipType(db.Model):
user = db.ReferenceProperty(UserModel)
membership_type = db.ReferenceProperty(MembershipType)
membership_active = db.BooleanProperty(default = False)
class ActivationStatus(db.Model):
user = db.ReferenceProperty(UserModel)
activated = db.BooleanProperty(default = False)
class WeeklyLimits(db.Model):
user = db.ReferenceProperty(UserModel)
membership_type = db.ReferenceProperty(MembershipType)
documents_left = db.IntegerProperty(default = 0)
我在生产中使用的代码确实更好地利用了各种实体的缓存,但是for循环仍然需要在一群用户中循环,才能最终找到需要对其进行操作的少数用户。理想情况下,我会过滤掉所有不符合标准的用户,然后开始在用户列表中循环——有没有什么灵丹妙药可以让我在这里实现这一点?
您可能正在寻找的魔法是非规范化。在我看来,这些类都可以有意义地组合成一个模型:
class Membership(db.Model):
user = db.ReferenceProperty(UserModel)
membership_class = db.StringProperty()
membership_code = db.StringProperty()
live = db.BooleanProperty(default = False)
membership_active = db.BooleanProperty(default = False)
activated = db.BooleanProperty(default = False)
documents_left = db.IntegerProperty(default = 0)
然后,您可以使用一个查询来完成所有的筛选。
过度规范化是AppEngine开发中常见的反模式。您发布的模型看起来就像是关系数据库的表定义(尽管,即使在这种情况下,它是否也比所需的划分得更多是有争议的),AppEngine的数据存储在很大程度上是而不是关系数据库。
你能看到将所有这些字段存储在一个模型中有什么缺点吗?
您可以通过将数据更紧密地存储在单个模型中来改进这一点。例如,UserMembership
的单个实体可以具有您需要的所有字段,并且您可以执行单个查询:
.filter("membership_type =", "FREE").filter("status =", "ACTIVE").filter("documentsLeft >", 0)
这将需要定义一个额外的索引,但运行速度会快得多。
如果您想避免按照其他两个答案中的建议对数据进行非规范化,您还可以考虑使用Google的新SQL服务,而不是普通的数据存储:http://googleappengine.blogspot.com/2011/10/google-cloud-sql-your-database-in-cloud.html
使用SQL,您可以在单个查询中完成所有这些操作,甚至可以使用单独的实体。