我使用的是 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 低?
以下是您可以检查/尝试的一些内容:
values
或 values_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/