1

我遇到了一个奇怪的查询性能问题,我很难理解。

以下是我所拥有的模型结构的简化版本,希望足以说明问题:

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部分是罪魁祸首。更改过滤器以使用formorname字段可以消除问题。

在代码中:

# 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 不会运行缓慢。

更新:

在尝试评论中提出的建议时,上述示例突然不再受此问题的困扰 - 在我找到任何有关原因的证据之前,更不用说实施修复了。我仍然不知道问题是什么,但现在我没有办法重现它以便进一步调查。

4

0 回答 0