2011-11-10 112 views
1

我的代码中有一个重复模式,其中模型有一个跟踪其历史/状态的相关模型(一对多)。这个相关模型可以有许多对象表示模型状态的时间点快照。Django ORM查询找到所有没有最近相关对象的对象

例如:

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中继)和Postgres 9.1运行。

回答

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/

+0

我跑测试查询和它非常缓慢(仍然在一小时后运行)。我在创建的字段上有一个索引。这个表虽然很大(5000万行左右)。 – erikcw

+0

这就是您需要开始研究数据库优化的关键。为实例提供更多的RAM,将数据库移动到它自己的实例,如果它尚未被隔离,甚至建立一个集群,但是我刚刚给你的是最有效的你将会得到的优化查询本身。 –

0

一个DB指数添加到created

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

作为一个经验法则,即在使用的任何列查询或排序的查询应该被编入索引,除非编写操作非常繁重(在这种情况下,您应该考虑使用单独的搜索索引,也许)。

使用没有索引的db列的查询只有这么快。如果您想更详细地分析查询瓶颈,请打开日志记录以获取更长时间的运行语句(例​​如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/

相关问题