【问题标题】:How to efficiently make app-engine-ndb subqueries on properties of KeyProperty linked entities?如何有效地对 KeyProperty 链接实体的属性进行 app-engine-ndb 子查询?
【发布时间】:2015-11-12 21:35:41
【问题描述】:

随着时间的推移,组建的团队可能会部署到多个项目

在此示例中,我只想查询分配给“活动”项目的团队。我正在使用的代码正在运行,但我想知道是否有更有效/更紧凑的方法。

模型

class Team(ndb.Model):
    """Model for representing an project team."""
    teamid = ndb.StringProperty(required=True)
    project = ndb.KeyProperty(kind='Project', required=True, repeating=True)

class Project(ndb.Model):
    """Model for representing a Project"""
    name = ndb.StringProperty(required=True)
    status = ndb.StringProperty(required=True)

查询

status = 'active'

project_query = Project.query()\
    .filter(Project.status == status)

active_projects = project_query.fetch(1000, keys_only=True)

team_query = Team.query().order(Team.teamid)\
    .filter(Team.projectid.IN(active_projects))

results = team_query.fetch(max_results, offset=start_at)

紧凑的形式本质上是一样的

team_query = Team.query().order(Team.teamid)\
    .filter(Team.projectid.IN(Project.query().filter(Project.status == status)
        .fetch(1000, keys_only=True)))

有没有更好的办法?

【问题讨论】:

  • 检查appstats 将是您确定的最佳方式。您绝对应该对活动项目执行keys_only= 查询,然后在查询Team 时使用这些键。
  • 这就是我已经在做的事情。紧凑的形式与比较没有任何不同 - 我想知道是否有一种根本不同的方式来处理它
  • 不,考虑到您帖子中的上下文,您的方式是最有效的。
  • 另一种方法是存储团队的密钥,同时与项目相关。然后查询活动项目,然后你就有了团队..
  • 是的。您需要从效率的角度考虑您需要什么。在某些情况下,链接实体(存储团队和项目的密钥以及您需要的任何摘要数据)可能更有效。除非您需要向下钻取,否则不需要映射。第一个视图的所有结果都将在一个查询中。

标签: python google-app-engine google-cloud-datastore app-engine-ndb


【解决方案1】:

您可以通过在 Team 实体上“冗余地”拥有 project_status 属性来反规范化您的数据模型,并保持与相应 Project 实体上的 status 属性相同。

当然,缺点是“更改项目的状态”还需要找到分配给该项目的所有团队并相应地更改他们的 project_status(您可能需要为此进行多实体组事务)。但最大的好处是定位所有分配给某个状态的项目的团队变得更快,只需一个简单的查询。

这种权衡对于与非规范化数据模型相关的决策非常典型。如果在您的应用程序中,项目状态变化相对较少(可能通常很少有团队被分配给给定项目),而“所有团队分配给处于特定状态的项目”的查询很频繁并且需要快速,那么 de -规范化将是一个值得优化的优化。

更抽象地说,哪些去规范化是值得的,总是高度依赖于特定的应用程序约束——哪些查询或更新是罕见的或频繁的,每个操作的性能目标是什么。由于有些东西是重复的,因此您也总是要为拥有更多数据而付出代价。另一方面,许多应用程序的写入/更新相对较少,读取/查询非常频繁,这确实倾向于明智的反规范化。

【讨论】:

    【解决方案2】:

    由于团队和项目之间存在多对多关系,因此您可以选择是否让团队具有:

    project = ndb.KeyProperty(kind='Project', required=True, repeating=True)
    

    或项目:

    team = ndb.KeyProperty(kind='Team', required=True, repeating=True)
    

    您可以通过仅使用一个查询和一个 ndb.get_multi() 来改进查询中的查询。查询很慢,Gets 更快(尤其是在 memcached 时)。通过更改模型,您可以改进查询。

    class Team(ndb.Model):
        """Model for representing an project team."""
        teamid = ndb.StringProperty(required=True)
    
    class Project(ndb.Model):
        """Model for representing a Project"""
        name = ndb.StringProperty(required=True)
        status = ndb.StringProperty(required=True)
        team = ndb.KeyProperty(kind='Team', required=True, repeating=True)
    

    现在您可以按状态查询并执行获取:

    status = 'active'
    
    project_query = Project.query()\
        .filter(Project.status == status)
    
    active_projects = project_query.fetch(1000, keys_only=True)
    
    teams = set()
    for project in active_projects:
        teams.extend(project.team)
    
    results = ndb.get_multi(list(teams))
    

    (感谢 Tim Hoffman 对这种方法的评论。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-04-14
      • 2017-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多