当查询集按相关模型中的字段排序时,性能会急剧下降。我用的是mysql。
例如我有两个模型:
class Event(models.Model):
idEvent = models.BigAutoField(primary_key=True)
created_at = models.DateTimeField(db_index=True, verbose_name=_('date'))
processed_at = models.DateTimeField(auto_now_add=True, verbose_name=_('processed'))
data = models.TextField()
class Meta:
ordering = ["-created_at"]
# [1154519 rows]
class AccessHistory(models.Model):
event = models.ForeignKey(Event, on_delete=models.CASCADE, blank=True, null=True)
result = models.TextField(verbose_name=_('result'))
# [1130603 rows]
如果我这样做
AccessHistory.objects.all().select_related('event').order_by('-event__created_at')
查询延迟超过 5 秒,如果我将 select_lated 与 prefetch_lated 交换,我会得到相同的延迟。当我在没有订购的情况下执行查询时,它会在预期时间内响应(<1s)
-- AccessHistory.objects.all().select_related('event').order_by('-event__created_at')
SELECT `history_accesshistory`.`id`,
`history_accesshistory`.`event_id`,
`history_accesshistory`.`result`,
`history_event`.`idEvent`,
`history_event`.`created_at`,
`history_event`.`processed_at`,
`history_event`.`data`
FROM `history_accesshistory` LEFT OUTER JOIN `history_event` ON (`history_accesshistory`.`event_id` = `history_event`.`idEvent`)
ORDER BY `history_event`.`created_at` DESC
-- AccessHistory.objects.all().prefetch_related('event').order_by('-event__created_at')
SELECT `history_accesshistory`.`id`,
`history_accesshistory`.`event_id`,
`history_accesshistory`.`result`
FROM `history_accesshistory` LEFT OUTER JOIN `history_event` ON (`history_accesshistory`.`event_id` = `history_event`.`idEvent`)
ORDER BY `history_event`.`created_at` DESC
我尝试使用 select_lated、prefetch_lated、在事件模型中对created_at 字段进行索引,并在事件模型中设置默认顺序。这并不能改善响应时间。
如何在不将created_at字段移动/复制到AccessHistory模型的情况下对其进行优化?
根据 文档您可能会遇到什么:
默认情况下,索引是按每列的升序创建的。
models.DateTimeField(db_index=True)
可能正在设置 ASC 索引,但您正在查询相反的内容。请注意,Django 5.0 文档当前也建议使用 Meta.indexes
而不是 Field.db_index
。
尝试像这样添加索引:
class Event(models.Model):
...
class Meta:
indexes = [
models.Index(fields=['-created_at'])
]
QuerySet.explain()
也可能有助于验证查询实际使用哪些索引。