Как оптимизировать сложный запрос django 1,8 - PullRequest
2 голосов
/ 09 января 2020

У меня запрос, выполнение которого занимает около 36 секунд, это нежизнеспособно, я пытался использовать select_related и prefetch, но результаты не улучшаются.

Это мой запрос:

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

emp is:

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')

И ater:

_candidates.count()

This 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, последователи - m2m в модели Job

Ответы [ 2 ]

2 голосов
/ 09 января 2020

Отличное предложение от @WillemVanOnsem. Я просто прилагаю документацию Django.

В соответствии с документацией Django

Соображения производительности

Будьте осторожны при использовании вложенных запросов и разберитесь в вашей базе данных характеристики производительности сервера (в случае сомнений, эталон!). Некоторые серверные базы данных, особенно MySQL, не очень хорошо оптимизируют вложенные запросы. В этих случаях более эффективно извлечь список значений и затем передать его во второй запрос. То есть, выполнить два запроса вместо одного:


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

entries = Entry.objects.filter(blog__in=list(values))

Обратите внимание на вызов list () вокруг блога QuerySet для принудительного выполнения первого запроса. Без этого вложенный запрос был бы выполнен, потому что QuerySets ленивы.

Я делаю особый акцент на "Обратите внимание на вызов list () вокруг Blog QuerySet для принудительного выполнения первого запрос. Без него будет выполнен вложенный запрос, потому что QuerySets ленивы. "

Надеюсь, это поможет

2 голосов
/ 09 января 2020

Я думаю, что причина того, что это занимает так много времени, заключается в том, что база данных выполняет подзапрос для каждого элемента в вашей таблице combo_candidate, и, таким образом, если число кандидатов велико, тогда будет много подзапросов.

Тем не менее, подзапрос является "stati c": он не требует многократной оценки, поскольку ничего в подзапросе не относится к миру "вне" запроса. Таким образом, мы можем сделать два запроса здесь: один, где оценивают подзапрос, и другой, где мы оцениваем внешний запрос.

Мы можем форсировать оценку, например, используя list(..):

_candidates = Candidate.objects.filter(
    job__in=<b>list(</b>job_list<b>)</b>,
    apply_date__range=[date_initial, date_end]
).order_by('-apply_date')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...