Django-改进M2M过滤中__in查询集的性能 [英] django - improve performance of __in queryset in M2M filtering

查看:14
本文介绍了Django-改进M2M过滤中__in查询集的性能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个与另一个模型具有M2M关系的模型。

这些是我的型号:

class Catalogue(models.Model):
    city = models.CharField(db_index=True,max_length=100, null=True)
    district = models.CharField(db_index=True,max_length=100, null=True)
    type = models.ManyToManyField(Type, db_index=True)
    datetime = models.CharField(db_index=True, max_length=100, null=True)


class Type(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name

这是views.py:

class all_ads(generic.ListView):
    paginate_by = 12
    template_name = 'new_list_view_grid-card.html'
    def get_queryset(self):
        city_district = self.request.GET.getlist('city_district')
        usage = self.request.GET.get('usage')
        status = self.request.GET.get('status')

        last2week = datetime.datetime.now() - datetime.timedelta(days=14)

        status = status.split(',')

        if usage:
            usage = usage.split(',')
        else:
            usage = ['1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31']

        intersections = list(set(status).intersection(usage))
        type_q = (Q(type__in=intersections) & Q(type__isnull=False))

        result = models.Catalogue.objects.filter(
            Q(datetime__gte=last2week) &
            type_q &
            ((reduce(operator.or_, (Q(city__contains=x) for x in city_district)) & Q(city__isnull=False)) |
             (reduce(operator.or_, (Q(district__contains=x) for x in city_district)) & Q(district__isnull=False)))
        ).distinct().order_by('-datetime').prefetch_related('type')

        return result

我想对带有一些查询的MySQL数据库进行过滤操作,并在列表视图中返回结果。

它在小型数据库上运行良好,但对于大型数据库,返回结果需要10秒以上的时间。如果删除type_q查询,则需要2秒(减少10秒!)。

如何提高__in查询集的性能?

推荐答案

看起来type_q本身并不是真正的罪魁祸首,而是起到了乘数的作用,因为现在我们做了一个LEFT OUTER JOIN,因此__contains遍历了所有的组合。因此,这更是两个一起工作的筛选器的特性

我们可以使用:

省略此操作
cat_ids = list(Catalogue.objects.filter(
    Q(*[Q(city__contains=x) for x in city_district], _connector=Q.OR) |
    Q(*[Q(district__contains=x) for x in city_district], _connector=Q.OR)
).values_list('pk', flat=True))

result = models.Catalogue.objects.filter(
    Q(datetime__gte=last2week),
    type_q,
    pk__in=cat_ids
).distinct().order_by('-datetime').prefetch_related('type')

某些数据库(MySQL知道不是优化子查询),甚至可以用来优化子查询。因此,这里我们没有物化列表,但是让Django使用子查询:

cat_ids = Catalogue.objects.filter(
    Q(*[Q(city__contains=x) for x in city_district], _connector=Q.OR) |
    Q(*[Q(district__contains=x) for x in city_district], _connector=Q.OR)
).values_list('pk', flat=True)

result = models.Catalogue.objects.filter(
    Q(datetime__gte=last2week),
    type_q,
    pk__in=cat_ids
).distinct().order_by('-datetime').prefetch_related('type')

这篇关于Django-改进M2M过滤中__in查询集的性能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆