[英]How can I improve this Django query?
我有这个 Django 查询需要几分钟才能运行。
stat_type = 'Some String'
obj = xxx # some brand object
query = Q( Q(stat_type__icontains=stat_type) & Q(Q(brand=obj) | Q(organisation__in=obj.organisation_set.active())))
result = ViewStat.objects.filter(query).aggregate(one=Count('id', filter=Q(created__gte=timezone.now() - relativedelta(months=int(1)))), \
three=Count('id', filter=Q(created__gte=timezone.now() - relativedelta(months=int(3)))),
twelve=Count('id', filter=Q(created__gte=timezone.now() - relativedelta(months=int(12)))),
all=Count('id', filter=Q(created__gte=timezone.now() - relativedelta(months=int(999)))))
楷模
class Brand(models.Model):
...
class Organisation(models.Model):
brand = models.ForeignKey(Brand, on_delete=models.CASCADE)
...
class ViewStat(models.Model):
stat_type = models.CharField(max_length=21)
brand = models.ForeignKey(Brand, on_delete=models.SET_NULL, blank=True, null=True)
organisation = models.ForeignKey(Organisation, on_delete=models.SET_NULL, blank=True, null=True)
我有大约 8 万个组织、700 个品牌和 1000 万个 ViewStats。
如何提高查询性能?
如果没有衡量标准进行比较,就很难做出改进。 但这里有一些想法。
首先,我对代码进行了一些重新排序,以便更好地理解它。
from django.db.models import Count, Q
from django.utils import timezone as tz
from .models import Brand, ViewStat
stat_type = 'Some String'
some_brand = Brand.objects.first()
active_org_id_set = set(
some_brand.organisation_set.active().values_list('id', flat=True))
time_now = tz.now()
one_month_ago = time_now - relativedelta(months=int(1))
three_months_ago = time_now - relativedelta(months=int(3))
twelve_months_ago = time_now - relativedelta(months=int(12))
result = ViewStat.objects.select_related(None)\
.filter(stat_type__icontains=stat_type)\
.filter(
Q(
Q(brand_id=some_brand.pk)
| Q(organisation_id__in=active_org_id_set)))\
.aggregate(
one=Count('id', filter=Q(created__gte=one_month_ago),
three=Count('id', filter=Q(created__gte=three_months_ago)),
twelve=Count('id', filter=Q(created__gte=twelve_months_ago)),
all=Count('id')))
对tz.now()
使用一次调用总是更好。
似乎可以省略聚合中的最后一个过滤器(使用relativedelta(999)
)。
我更喜欢使用单独的变量来保存过滤器数据,所以我创建了active_org_id_set
。 请注意,我只是收集到 PK(使用.values_list()
),而不是整个Organisation
对象,因此消耗的 memory 少了很多。
然后我使用这个active_org_id_set
并使用organisation_id__in
而不是organisation__in
,这样就不需要将Organisation
表与ViewStat
表连接起来。
我还过滤brand_id
而不是brand
,以避免将Brand
表与ViewStat
表连接起来。
我明确使用.select_related(None)
将连接的表减少到最低限度。 也许这个调用不是必需的,但我无权访问您的数据库执行计划。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.