Django ORM - 使用 M2M 加速过滤器

标签 django orm

我使用的是 Django 1.4、Python 2.7、Ubuntu 14.04 和 PostgreSQL 9.3。

我有 2 个通过多对多 (M2M) 关系相关联的模型。针对 M2M 关系进行过滤时,我遇到了主要的性能问题。

class Meat(models.Model):
    name1 = models.CharField(max_length=200)
    name2 = models.CharField(max_length=200)

class Potato(models.Model):
    bad_meats = models.ManyToManyField(
        Meat, null=True, blank=True, related_name="bad_potatoes")

我正在将 Meat 查询集上的过滤器链接在一起。
potato = Potato.objects.get(pk=12345)
qs = Meat.objects.all()
qs = qs.filter(name1='foo')
qs = qs.filter(name2='bar')
qs = qs.exclude(id__in=potato.bad_meats.all())

使用 __in正在显着减慢此过滤过程。有人可以建议另一种方法可以加快速度吗?

我不能使用 .raw()查询,因为我需要根据某些条件在整个过程中链接过滤器。

要提供更多详细信息,请访问 Meat表有大约 150,000 行和 potato.bad_meats.all()有大约 40,000 个结果。此查询当前需要大约 8-10 秒。我需要把这个降到 1 秒以下。

最佳答案

150K 行和 40K 关系似乎没有那么大需要 8s,也许你的机器 CPU 低?

以下是您可以检查/尝试的一些内容:

  • 您是否检查过数据库结构中相关列的索引和外键?
  • 您是否尝试在 name1 和 name2 列上添加索引?
  • 您还应该尝试监控 Python 代码在原始结果和模型之间进行映射所花费的时间,它可能比查询时间更重要。您可以尝试使用 valuesvalues_list获取字典/列表而不是模型对象。

  • 关于 db 查询,我发现了一个稍微快一点的查询(但在我的机器上这并不重要)。
    我创建了一个包含 150K 肉和 1 个与 40K 肉相关的土 bean 的数据库。使用与您相同的方法在我的 2.3Gz 机器上运行不到 1 秒。

    我像这样打印了生成的查询
    >>> qs = Meat.objects.filter(name1='foo').filter(name2='bar').exclude(id__in=potato.bad_meats.all())
    >>> print qs.query
    SELECT "coucou_meat"."id", "coucou_meat"."name1", "coucou_meat"."name2" 
    FROM "coucou_meat" 
    WHERE ("coucou_meat"."name1" = foo  AND "coucou_meat"."name2" = bar 
    AND NOT ("coucou_meat"."id" IN
        (SELECT U0."id" 
        FROM "coucou_meat" U0 
        INNER JOIN "coucou_potato_bad_meats" U1 ON (U0."id" = U1."meat_id") 
        WHERE U1."potato_id" = 1 )))
    

    我尝试直接在 pgadmin 中运行它,查询耗时 325 毫秒。

    然后我尝试了一个稍微不同的查询:
    >>> qs = Meat.objects.filter(name1='foo').filter(name2='bar').exclude(bad_potatoes__id=12345)
    >>> print qs.query
    SELECT "coucou_meat"."id", "coucou_meat"."name1", "coucou_meat"."name2" 
    FROM "coucou_meat" WHERE ("coucou_meat"."name1" = foo  AND "coucou_meat"."name2" = bar  
    AND NOT (("coucou_meat"."id" IN 
        (SELECT U1."meat_id" 
        FROM "coucou_potato_bad_meats" U1 
        WHERE (U1."potato_id" = 1  AND U1."meat_id" IS NOT NULL)) 
            AND "coucou_meat"."id" IS NOT NULL)))
    

    在 pgadmin 中运行它并获得 230 毫秒的执行时间。由于它有点快,您可以尝试看看它是否有任何不同。

    关于Django ORM - 使用 M2M 加速过滤器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25084759/

    相关文章:

    python - pytest fixture 的多个副本

    java - JHipster:错误:Image和ImageType的关系中,ImageType没有声明

    javascript - 为什么我没有实体的引用 ID?

    django - 如何让游戏在通过 facebook 玩时使用 https,在从其他域玩时使用 http

    python - 如何在 Django 中选择不同的值?

    django - SMTPSenderRefused at/(501, b'5.1.7 无效地址 [MAXPR01MB0396.INDPRD01.PROD.OUTLOOK.COM ]', ' =?utf-8?q?Your?=')

    python - 如何使用 MongoDB 在 Django 中的 request.user 中设置 User

    java - JPA:如何将字符串持久化到数据库字段中,键入 MYSQL 文本

    python - 使用 Django ORM 加入同一张表

    php - 需要 Laravel DB 查询帮助