Django:我如何避免不必要的SQL语句?

时间:2012-03-14 15:20:37

标签: python sql django

我正在优化我们(第一个)Django项目中的慢页面加载。整个项目确实测试状态管理,因此存在具有计划执行的案例的协议。目前代码是:

protocols = Protocol.active.filter(team=team, release=release)
cases = Case.active.filter(protocol__in=protocols)
caseCount = cases.count()
plannedExecs = Planned_Exec.active.filter(case__in=cases, team=team, release=release)

# Start aggregating test suite information 
# pgi Model
testSuite['pgi_model'] = []
for pgi in PLM.objects.filter(release=release).values('pgi_model').distinct():
    plmForPgi = PLM.objects.filter(pgi_model=pgi['pgi_model'])
    peresults = plannedExecs.filter(plm__in=plmForPgi).count()
    if peresults > 0:
        try:
            testSuite['pgi_model'].append((pgi['pgi_model'], "", "", peresults, int(peresults/float(testlistCount)*100)))
        except ZeroDivisionError:
            testSuite['pgi_model'].append((pgi['pgi_model'], "", "", peresults, 0))

# Browser
testSuite['browser'] = []
for browser in BROWSER_OPTIONS:
    peresults = plannedExecs.filter(browser=browser[0]).count()
    try:
        testSuite['browser'].append((browser[1], "", "", peresults, int(peresults/float(testlistCount)*100)))
    except ZeroDivisionError:
        testSuite['browser'].append((browser[1], "", "", peresults, 0))

# ... more different categories are aggregated below, then the report is generated...

这段代码制作了很多SQL语句。 PLM.objects.filter(release=release).values('pgi_model').distinct()返回50个字符串的列表,两个过滤操作都为每个字符串执行一条SQL语句,这意味着只有100个SQL语句用于循环。 (此外,似乎应将values_listflat=True一起使用。)

由于我想获取有关相关案例和计划执行的信息,我认为我真的只需要检索这两个表,然后对此进行一些分析。使用filter和count()似乎是当时显而易见的解决方案,但我想知道我是不是更好的只是使用.values()构建相关案例的dict和计划执行信息,然后分析它,所以为了避免不必要的SQL语句。任何有用的建议?谢谢!

编辑:在尝试对此进行分析以了解时间的变化时,我正在使用Django Debug工具栏。它解释说有超过200个查询,每个查询都运行得非常快,因此整体而言它们占用的时间非常短。但是,可能是SQL的执行速度相对较快,但是ORM的构建会增加,因为它发生了200多次?我重构了一个前一页,加载了3分钟,并使用了values()而不是ORM,从而使页面加载时间减少到2.7秒和5个SQL语句。

2 个答案:

答案 0 :(得分:1)

创建查询集不会访问数据库;只访问它的结果。因此,仅创建查询集不是您的问题。

请注意,将查询集传递到另一个查询集不会创建两个查询。因此,构建dicts不会减少数据库命中数。

如果你可以构建dicts,那么你可能会创建一个比其他方式更简单的查询,这将加快实际的查询执行速度。然而,这是一个单独的问题。

答案 1 :(得分:1)

这反映了我作为反向外键查找的情况。我们应该能够通过在发布中获取与PLM相关联的所有pgi_model来减少top for循环。我假设你有一个PGI模型,PLM模型有一个名为pgi_model的外键字段。如果是这种情况,您可以使用以下内容在PLM版本中找到PGI。你仍然有一个循环,但理论上应该减少循环的迭代:

pgis = PGI.objects.filter(plm__in=PLM.objects.filter(release=release))
for pgi in pgis:
    peresults = plannedExecs.filter(plm=pgi.plm).count()
    if peresults > 0:
        try:
            testSuite['pgi_model'].append((pgi['pgi_model'], "", "", peresults, int(peresults/float(testlistCount)*100)))
        except ZeroDivisionError:
            testSuite['pgi_model'].append((pgi['pgi_model'], "", "", peresults, 0))