Что быстрее, обратный поиск в фильтре или прямой поиск в pks в Django ORM? - PullRequest
0 голосов
/ 27 июня 2018

У меня есть структура модели Django, которая выглядит следующим образом:

# Pre-defined User model

class A(models.Model):
    pass

class B(models.Model):
    relevant_users = models.ManyToManyField(User)
    related_A = models.ForeignKey(A)

И учитывая User, я хочу быстро сгенерировать набор запросов всех A, привязанных к B, где пользователь находится в relevant_users «многие ко многим». Я ожидаю много A, но только один или два B на A, с индексацией только на pk.

У меня есть два метода для генерации этого набора запросов, и оба работают:

Метод 1: Фильтровать объекты с обратным поиском.

queryset = A.objects.filter(B__relevant_users__exact=user)

Метод 2: Получите список A pks с прямым поиском, затем найдите эти pks в таблице A. (select_related используется, но здесь опущено для ясности)

a_pks = [b.related_A.pk for b in user.b_set.all()]
queryset = A.objects.filter(pk__in=a_pks)

Это эквивалентно? Имеют ли они одинаковую сложность по времени для больших чисел А?

edit: похоже, что способ 2 в некоторых случаях быстрее:

для малонаселенных relevant_users (в основном пусто):

A: 10000 м1: 0,0014 с м2: 0,0024 с

A: 100 000 м1: 0,0016 с м2: 0,0028 с

Для густонаселенных relevant_users (все B имеют хотя бы одного пользователя):

A: 10000 м1: 0,040 с м2: 0,019 с

A: 20000 м1: 0,066 с м2: 0,031 с

1 Ответ

0 голосов
/ 27 июня 2018

В способе 2 выполняются два обращения к базе данных, что, естественно, почти в два раза медленнее, чем в способе 1, для которого требуется только одно обращение. Избегайте выполнения двух запросов, когда вы можете сделать только один, если только один запрос не требует чрезмерно сложной агрегации, которая иногда может выполняться быстрее на стороне клиента в python.

...