多年来一直运行正常的简单查询,突然变得非常缓慢

7

我有一个查询已经运行了大约两年,一直很正常。这个数据库表大约有5000万行数据,并且增长缓慢。但是最近一周,我的一个查询从几乎瞬间返回结果变成了需要数小时才能运行完毕。

Rank.objects.filter(site=Site.objects.get(profile__client=client, profile__is_active=False)).latest('id')

我将缓慢查询的范围缩小到Rank模型。似乎与使用latest()方法有关。如果只请求一个queryset,它会立即返回一个空的queryset。

#count returns 0 and is fast
Rank.objects.filter(site=Site.objects.get(profile__client=client, profile__is_active=False)).count() == 0
Rank.objects.filter(site=Site.objects.get(profile__client=client, profile__is_active=False)) == [] #also very fast

以下是运行EXPLAIN的结果。http://explain.depesz.com/s/wPh 以下是运行EXPLAIN ANALYZE的结果。http://explain.depesz.com/s/ggi 我尝试过对表进行了vacuum操作,但没有改变。字段“site”(外键)已经建立了索引。
奇怪的是,如果我为已经与Rank对象关联的另一个客户端运行相同的查询,那么查询再次非常快地返回。因此,似乎只有当该客户端没有Rank对象时才会出现问题。
有什么想法吗?
版本: Postgres 9.1, Django 1.4 svn trunk rev 17047
2个回答

0

latest通常用于日期比较,也许你应该尝试按id降序排序,然后限制为一个。


我尝试了那个,也有类似长时间的延迟。当我查看ORM生成的原始SQL时,两者产生了等效的输出。 - erikcw

0

好的,你没有展示实际的SQL语句,所以这让人很难确定。但是,解释输出表明它认为找到匹配的最快方法是通过反向扫描“id”上的索引直到找到相关客户。

由于你说直到最近它一直很快,这可能不是一个愚蠢的选择。然而,总有一个特定客户记录在这个搜索的最远端的机会。

所以-首先尝试两件事:

  1. 对相关表运行分析,看看是否给规划器提供了足够的信息。
  2. 如果没有,请增加相关列的统计数据(ALTER TABLE ... SET STATISTICS)并重新分析。看看它是否奏效。

http://www.postgresql.org/docs/9.1/static/planner-stats.html

如果这仍然没有帮助,那么考虑在(客户端,ID)上建立索引,并删除ID上的索引(如果在其他地方不需要)。这应该能够让你得到闪电般快速的答案。

在WHERE字段和ORDER BY字段上设置复合索引就解决了问题。原来查询规划器一直在整个索引中扫描以进行排序,然后再过滤数据。而复合索引解决了这个问题。 - erikcw

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接