Django ORM查询查找没有最近相关对象的所有对象

时间:2011-11-10 16:32:39

标签: python django postgresql django-models

我的代码中有一个重复模式,其中模型具有跟踪其历史/状态的相关模型(一对多)。此相关模型可以包含许多对象,这些对象表示模型状态的时间点快照。

例如:

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天内没有订阅更新或类似情况的所有“配置文件”对象。我一直在使用子选择查询来实现这个目标:

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 Trunk)和Postgres 9.1。

2 个答案:

答案 0 :(得分: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/

答案 1 :(得分:0)

将数据库索引添加到created

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

根据经验,在查询或排序查询中使用的任何列都应编入索引,除非您在编写操作时很重要(在这种情况下,您应该考虑使用单独的搜索索引)。

使用没有索引的db列进行查询的速度非常快。如果要更详细地分析查询瓶颈,请打开更长时间运行语句的日志记录(例如200毫秒及以上),并对长时间运行的查询执行explain analyze(postgres)。

编辑: 我现在才在你的评论中看到你在这个领域有一个索引。在这种情况下,更有理由查看explain analyze的输出。

  1. 确保索引真正使用,并完全扩展。
  2. 查看postgres是否不必要地写入磁盘而不是使用内存
  3. 请参阅 - 关于查询计划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/