我遇到了一个奇怪的查询性能问题,我很难理解。
以下是我所拥有的模型结构的简化版本,希望它足以说明问题:
class Note(models.Model):
...
name = models.CharField(max_length=50)
parentNote = models.ForeignKey('self', null=True)
form = models.ForeignKey('NoteForm', null=True)
...
class Event(Note):
...
startDate = models.DateField()
...
class Activity(Event):
...
Activity
模型是我面临的问题的根源。它具有广泛的继承层次,其中没有一个是抽象的。我不知道这是否有助于解决这个问题。 Activity
有大约280000条记录,显然,它的父母至少有那么多,如果不是更多的话。
上面没有描述NoteForm模型 - 只需知道它在Activity
模型的层次结构外部并且包含少于100条记录。
我正在使用Django 1.3版。
查询某些父Activity的最新“子”活动时出现问题。查询按parentNote
字段过滤,按'startDate'字段排序(降序)并使用Python的索引表示法选择第一个结果(根据我的理解,只是将LIMIT 1
添加到生成的SQL中)。请参阅下面的代码。
此查询在未找到结果的情况下意外缓慢运行 - 10秒以上。如果找到结果,它会按预期运行 - 远低于1秒。
进一步调查显示以下内容:
parentNote
过滤器部分是罪魁祸首。更改过滤器以使用form
或name
字段可以解决问题。在代码中:
# Original - SLOW
try:
latest = Activity.objects.filter(
parentNote=activity.pk
).order_by('-startDate')[0]
except IndexError:
latest = None
# FAST
# No limit
Activity.objects.filter(
parentNote=activity.pk
).order_by('-startDate')
# No ordering
try:
latest = Activity.objects.filter(
parentNote=activity.pk
)[0]
except IndexError:
latest = None
# Different filter
try:
latest = Activity.objects.filter(
form=activity.pk
).order_by('-startDate')[0]
except IndexError:
latest = None
# Different filter
try:
latest = Activity.objects.filter(
name=activity.pk
).order_by('-startDate')[0]
except IndexError:
latest = None
如果问题出在数据库级别,我看不到它。我在django-debug-toolbar
的{{1}}中运行了上面的“原始”和“无限制”示例。 “Original”花了16秒,“No Limit”花了59ms。我复制了debugsqlshell
打印的两个查询,并在pgAdmin中运行它们。 “原始”花了1375毫秒,“无限制”花了94毫秒。所以它更慢,但不是我看到使用ORM的数量。 debugsqlshell
肯定会显示查询分析器采用不同的路径,我完全理解。但我无法直接使用SQL重现16秒查询。
所以,总结一下:
更新
在尝试评论中提出的建议时,上述例子突然停止了这个问题 - 在我找到任何关于原因的证据之前,更不用说实施修复了。我仍然不知道问题是什么,但现在我没有办法重现它以便进一步调查。