Django ORM查询查找没有近期关联对象的所有对象

2 投票
2 回答
614 浏览
提问于 2025-04-17 06:03

我在代码中遇到一个重复的模式,就是一个模型有一个相关的模型(一个对多个),用来跟踪它的历史或状态。这个相关的模型可以有很多对象,表示模型状态的某个时刻快照。

举个例子:

class Profile(models.Model):
    pass

class Subscription(models.Model):
    profile = models.ForeignKey(Profile)
    data_point = models.IntegerField()
    created = models.DateTimeField(default=datetime.datetime)

#Example objects
p = Provile()
subscription1 = Subscription(profile=p, data_point=32, created=datetime.datetime(2011, 7 1)
subscription2 = Subscription(profile=p, data_point=2, created=datetime.datetime(2011, 8 1)
subscription3 = Subscription(profile=p, data_point=3, created=datetime.datetime(2011, 9 1)
subscription4 = Subscription(profile=p, data_point=302, created=datetime.datetime(2011, 10 1)

我经常需要查询这些模型,找出所有在过去3天内没有更新订阅的“Profile”对象,或者类似的情况。我一直在用子查询来实现这个:

q = Subscription.objects.filter(created__gt=datetime.datetime.now()-datetime.timedelta(days=3).values('id').query
Profile.objects.exclude(subscription__id__in=q).distinct()

但问题是,当表格很大的时候,这样做非常慢。有没有更高效的查询方式呢?也许可以让Django使用JOIN而不是SUBSELECT(看起来去掉那些内嵌的循环会有帮助)?

我想用ORM,但如果需要的话,我也愿意使用.extra()方法,甚至是原始SQL,只要能显著提高性能。

我使用的是Django 1.4alpha(SVN主干)和Postgres 9.1。

2 个回答

0

created 添加一个数据库索引:

created = models.DateTimeField(default=datetime.datetime, db_index=True)

一般来说,任何在查询中用来查找或排序的列都应该加上索引,除非你写入数据的操作特别多(在这种情况下,你可能需要考虑使用一个单独的搜索索引)。

如果查询使用的数据库列没有索引,速度就会受到限制。如果你想更详细地分析查询的瓶颈,可以开启日志记录,记录运行时间较长的语句(比如200毫秒及以上),然后对这些长时间运行的查询执行 explain analyze(在postgres中)。

编辑: 我刚刚在你的评论中看到你已经在这个字段上加了索引。在这种情况下,更应该查看 explain analyze 的输出。

  1. 确保索引确实被使用,并且使用到最大程度。
  2. 查看postgres是否不必要地写入磁盘,而是应该使用内存。

查看 - 关于查询规划的更多信息 http://www.postgresql.org/docs/current/static/runtime-config-query.html

也许这个链接可以作为一个入门参考: http://blog.it-agenten.com/2015/11/tuning-django-orm-part-2-many-to-many-queries/

0
from django.db.models import Max
from datetime import datetime, timedelta

Profile.objects.annotate(last_update=Max('subscription__created')).filter(last_update__lt=datetime.now()-timedelta(days=3))

聚合(和注解)非常棒,具体可以参考这个链接: https://docs.djangoproject.com/en/dev/topics/db/aggregation/

撰写回答