在 django 查询中使用带多个过滤器的 Count 函数注释的最优化方法是什么

问题描述 投票:0回答:1

例如在学校,有很多数据来存储例如“Class”,“Student”,“Book”等。另外,该模型使用了softdelete(softdelete是指删除时的操作只需将

is_deleted
更改为
True
在模型中)。每个模型中都有
create_time
update_time
is_delete
等。在我的代码中现在我使用下面的方法,运行sql至少花了30s。

那么使用包含很多条件的过滤器来查询

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

请帮助提供您知道的所有代码查询以及您认为可以优化以使用许多计数和过滤器进行计数的所有代码查询。

python sql django postgresql django-rest-framework
1个回答
0
投票

由于您每次都过滤掉已删除的书籍,因此您已经可以通过以下方式从所有计数中忽略这些书籍:

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])),
)

此外不要在同一查询中对不同的

JOIN
进行聚合:这会“炸毁”记录,因为现在我们每所学校的每本书和每个班级都有一行,这意味着您必须与
distinct=True
 [Django-doc]
会减慢进程,对您加入的每个表进行查询。因此,在这种情况下,一个用于书籍,一个用于课程,等等。在此类查询中,您可以对书籍进行不同的计数,就像上面的代码示例中所做的那样。

最后在

db_index=Trueis_deleted

 上添加 
create_time 
[Django-doc]
 以提高性能。

© www.soinside.com 2019 - 2024. All rights reserved.