【问题标题】:How optimze complex query django 1.8django 1.8如何优化复杂查询
【发布时间】:2020-01-09 12:36:15
【问题描述】:

我有一个查询需要大约 36 秒才能运行,这是不可行的,我尝试使用 select_related 和 prefetch,但结果没有改善。

这是我的查询:

job_list = Job.objects.filter(Q(hiring_manager=emp) | Q(
                        followers=emp)).values_list('pk', flat=True)

emp 是:

emp = Employee.objects.filter(
                        user=self.request.user, firm=obj).first().pk

然后我用在:

_candidates = Candidate.objects.filter(
                        job__in=job_list,
                        apply_date__range=[date_initial, date_end]
                    ).order_by('-apply_date')

然后吃:

_candidates.count()

这个 SQL:

SQL Executed:
SELECT ...
FROM `combo_candidate` WHERE (
    `combo_candidate`.`job_id` IN (
        SELECT ... FROM `combo_job` U0
        LEFT OUTER JOIN `combo_job_followers` U2 ON U0.`id` = U2.`job_id`
        WHERE U0.`hiring_manager_id` = 9482 OR U2.`user_id` = 9482
          AND `combo_candidate`.`apply_date` BETWEEN '2019-01-01 02:00:00' AND '2019-02-01 02:00:00'
    )
Time
33402,8768539 ms

hiring_manager 是 Job 中的 FK,followers 是 model Job 中的 m2m

【问题讨论】:

  • 这不是 this 查询集的查询,您在另一个 QuerySet 中使用 job_list
  • 我在_candidates = Candidate.objects.filter( job__in=job_list, apply_date__range=[date_initial, date_end] ).order_by('-apply_date') 及以后使用_candidates.count()
  • @GustavoNugueira:在这里单独运行子查询可能更有意义,例如Candidate.objects.filter(job__in=list(job_list), apply_date__range=...)
  • 哇这优化了大约 2 秒,你能给我解释一下吗?

标签: django performance django-queryset


【解决方案1】:

我认为这需要这么长时间的原因是因为数据库为您的combo_candidate 表中的每个元素运行子查询,因此如果候选的数量很高,那么它会产生很多子查询。

然而,子查询是“静态的”:它不需要被多次评估,因为子查询中没有任何东西指向查询“外部”的世界。因此,我们可以在这里进行两种查询:一种是评估子查询,另一种是我们评估外部查询。

我们可以强制评估,例如使用list(..)

_candidates = Candidate.objects.filter(
    job__in=list(job_list),
    apply_date__range=[date_initial, date_end]
).order_by('-apply_date')

【讨论】:

    【解决方案2】:

    @WillemVanOnsem 的出色建议。我只是附上 Django 文档。

    根据 Django 文档

    性能考虑

    谨慎使用嵌套查询并了解您的数据库 服务器的性能特征(如果有疑问,基准测试!)。一些 数据库后端,尤其是 MySQL,不优化嵌套查询 很好。在这些情况下,提取列表更有效 值,然后将其传递给第二个查询。即执行两个 查询而不是一个:

    
    values = Blog.objects.filter(
            name__contains='Cheddar').values_list('pk', flat=True)
    
    entries = Entry.objects.filter(blog__in=list(values))
    
    

    注意 Blog QuerySet 周围的 list() 调用以强制执行 第一个查询。没有它,将执行嵌套查询,因为 QuerySet 是惰性的。

    我特别强调 “请注意,围绕 Blog QuerySet 的 list() 调用强制执行第一个查询。没有它,将执行嵌套查询,因为 QuerySet 是惰性的。”

    希望对你有帮助

    【讨论】:

      猜你喜欢
      • 2012-01-07
      • 1970-01-01
      • 2012-09-22
      • 1970-01-01
      • 1970-01-01
      • 2020-11-19
      • 1970-01-01
      相关资源
      最近更新 更多