外键按字段排序时性能缓慢

问题描述 投票:0回答:1

当查询集按相关模型中的字段排序时,性能会急剧下降。我用的是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模型的情况下对其进行优化?

mysql django django-models django-queryset django-orm
1个回答
0
投票

根据 文档您可能会遇到什么:

默认情况下,索引是按每列的升序创建的。

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()
也可能有助于验证查询实际使用哪些索引。

© www.soinside.com 2019 - 2024. All rights reserved.