объединение набора запросов django не работает только с

#mysql #django #django-models #django-queryset

#mysql #django #django-models #django-queryset

Вопрос:

У меня есть 2 querysets , и я применяю union к ним, но странная вещь, когда я использую only , он выбирает все поля из базы данных, а когда я использую values , он выбирает только заданные поля.

Это выбор всех полей из Physician таблицы

 doctors_models.Physician.objects.filter(
    appointments__member=self.context['member']
).union(doctors_models.Physician.objects.filter(
    appointments__booked_by=self.context['member']
)).only('id', 'name_prefix', 'first_name', 'middle_name', 'last_name', 'name_suffix')
  

НО
Это выбор только указанных полей из Physician таблицы

 doctors_models.Physician.objects.filter(
    appointments__member=self.context['member']
).union(doctors_models.Physician.objects.filter(
    appointments__booked_by=self.context['member']
)).values('id', 'name_prefix', 'first_name', 'middle_name', 'last_name', 'name_suffix')
  

Тем не менее, это также выбор только указанных полей, но почему я должен определять поля 2 раза.

 doctors_models.Physician.objects.filter(
    appointments__member=self.context['member']
).only('id', 'name_prefix', 'first_name', 'middle_name', 'last_name', 'name_suffix').union(
    doctors_models.Physician.objects.filter(
        appointments__booked_by=self.context['member']
).only('id', 'name_prefix', 'first_name', 'middle_name', 'last_name', 'name_suffix'))
  

Комментарии:

1. если у вас есть объединение, обе части должны иметь одинаковое количество полей

2. Он имеет те же поля.

3. Нет, это не так, поскольку ограничивает только поля, которые используются в запросе SELECT, также вы можете сделать это правильно в одном запросе, используя Q objects, Уиллем уже подробно объяснил это

Ответ №1:

Тем не менее, это также выбор только указанных полей, но почему я должен определять поля 2 раза?

Поскольку количество столбцов и их типы в обоих SELECT операторах должны совпадать, как указано в документации по .union(…) :

Передача разных моделей работает до тех пор, пока SELECT список одинаков во всех QuerySet s (по крайней мере, типы, имена не имеют значения, если типы находятся в одном и том же порядке). В таких случаях вы должны использовать имена столбцов из первого QuerySet в QuerySet методах, применяемых к результирующему QuerySet .

При этом, пожалуйста, не используйте .union(…) в первую очередь для этого. Вы можете объединить два условия, обернув их в Q объекты и объединив их с помощью «или«:

 from django.db.models import Q

doctors_models.Physician.objects.filter(
    Q(appointments__member=self.context['member']) |
    Q(appointments__booked_by=self.context['member'])
).only('id', 'name_prefix', 'first_name', 'middle_name', 'last_name', 'name_suffix')  

Кроме того, использование .only(…) [Django-doc] или .defer(…) [Django-doc] рекомендуется только для столбцов, содержащих большой объем данных. Для «маленьких» столбцов это часто не оказывает существенного влияния, и в случае, если вам позже понадобятся эти поля, это может даже привести к проблемам N 1.

Комментарии:

1. 1. ИЛИ запрос приведет к тому, что «индекс не будет использоваться», поэтому используйте объединение. 2. использование only так, чтобы оно не извлекало все ненужные поля. 3. Вы сказали, что объединение работает, когда столбцы в обоих запросах одинаковы, и они есть в моем запросе. Вы видите разные столбцы?

2. @SHIVAMJINDAL: если вы отменяете оба столбца отдельно, обычно он будет использовать два индекса. Часто внутренняя база данных переписывает ее в ОБЪЕДИНЕНИЕ, но преимущество в том, что вы, таким образом, не пишете два SELECT оператора самостоятельно: orafaq.com/tuningguide/logical operators.html

3. @Willen Это где-то написано, что mysql автоматически преобразует ИЛИ запрашивает в объединение

4. @SHIVAMJINDAL: хорошая база данных собирает статистику и составляет план запроса на основе статистики. Если вы создаете запрос, и база данных ожидает вернуть огромный кусок строк, она не будет использовать индекс, сканирование таблицы будет более эффективным (поскольку, даже если он использует индекс, позже ему придется сканировать, чтобы вернуть записи). План запросов основан на избирательности индексов . Таким образом, это означает, что если число различных booked_by s в appointments отношении невелико, оно не будет использовать индекс.

5. @SHIVAMJINDAL: таким образом, план запроса определяется не только запросом, но и количеством записей, которые база данных ожидает получить. Если избирательность равна 0.7, ожидается получение большого количества записей.