我遇到了一个奇怪的查询性能问题,我很难理解。
以下是我所拥有的模型结构的简化版本,希望足以说明问题:
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 的最新“子”Activity 时会出现问题。查询按字段过滤parentNote
,按“startDate”字段(降序)排序,并使用 Python 的索引表示法选择第一个结果(据我了解,它只是添加LIMIT 1
到生成的 SQL 中)。请参阅下面的代码。
未找到结果时,此查询运行异常缓慢- 10 多秒。如果找到结果,它将按预期运行 - 不到 1 秒。
进一步调查发现:
- 这是导致问题的限制。只做过滤,不限于第一个结果,并不慢——不管结果是否找到。
- 订购部分是罪魁祸首。删除排序消除了问题。
- 过滤器
parentNote
部分是罪魁祸首。更改过滤器以使用form
orname
字段可以消除问题。
在代码中:
# 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
我已经在's 中运行了上面的“原始”和“无限制”示例 debugsqlshell
。“Original”耗时 16 秒,“No Limit”耗时 59ms。我复制了由 pgAdmin 打印的两个查询 debugsqlshell
并在 pgAdmin 中运行它们。“原始”耗时 1375 毫秒,“无限制”耗时 94 毫秒。所以它更慢,但不是我使用 ORM 看到的数量。EXPLAIN ANALYZE
绝对显示查询分析器采用不同的路径,我完全理解。但我无法直接使用 SQL 重现 16 秒查询。
所以,总结一下:
- 我看到 LIMIT 查询的运行速度比没有 LIMIT 的相同查询慢得多,但只有在没有找到结果的情况下。
- 返回结果的查询不会运行缓慢 - 除了过滤器的值之外,它们是相同的。
- 它似乎是过滤器中包含哪些字段以及查询集是否已排序的函数。
- 它似乎不是数据库级别的问题,因为直接运行 SQL 不会运行缓慢。
更新:
在尝试评论中提出的建议时,上述示例突然不再受此问题的困扰 - 在我找到任何有关原因的证据之前,更不用说实施修复了。我仍然不知道问题是什么,但现在我没有办法重现它以便进一步调查。