Как наиболее оптимально использовать функцию annotate with Count с фильтром many в запросе django
Например, в школе, есть много данных для хранения, например, "Класс", "Ученик", "Книга" и т.д. Также в модели используется softdelete (softdelete означает действие, когда при удалении достаточно изменить is_deleted
на True
в модели). В каждой модели есть create_time
, update_time
, is_delete
и т.д. В моем коде сейчас я использую метод ниже, на выполнение sql.
Каким образом наиболее оптимизирован запрос Count
с фильтром, содержащим множество условий? Также иногда нам нужно пересчитать ту же модель, но используя другой фильтр
Вот пример кода на Django (Проверка данных подсчета для каждой школы).
# In this code, each model already implements softdelete manager query.
School.objects.annotate(
number_of_class=Count(
"class", filter=Q(class__is_deleted=False, class__create_time__lte=datetime, ...more filter), distinct=True
),
number_of_student=Count(
"student", filter=Q(student__is_deleted=False, student__create_time__lte=datetime, ...more filter), distinct=True
),
number_of_public_book=Count(
"book", filter=Q(book__is_deleted=False, book__create_time__lte=datetime, book__create_time__gte=datetime, book__type=1, ...more filter), distinct=True
),
number_of_private_book=Count(
"book", filter=Q(book__is_deleted=False, book__create_time__lte=datetime, book__create_time__gte=datetime, book__type__in=[2,3], ...more filter), distinct=True
)
more_count...
)
Пожалуйста, помогите дать весь код запросов, который вы знаете и который, по вашему мнению, можно оптимизировать для подсчета с большим количеством графов и фильтров.
Поскольку вы каждый раз отфильтровываете удаленные книги, вы уже можете исключить их из всех подсчетов с помощью:
School.objects.filter(
book__is_deleted=False,
book__create_time__lte=datetime,
book__create_time__gte=datetime,
).annotate(
number_of_public_book=Count('book', filter=Q(book__type=1)),
number_of_private_book=Count('book', filter=Q(book__type__in=[2, 3])),
)
Furthermore don't make aggregates over different JOIN
s in the same query: this "blows up" records, since now we have a row per book and per class for each school, and this means you have to work with a distinct=True
[Django-doc] slowing down the process, make queries per table you join over. So in this case, one for the books, one for the classes, etc. In such queries you can batch different counts for books, like is done in the code sample above.
Наконец, добавьте db_index=True
[Django-doc] на is_deleted
и create_time
для увеличения производительности.