【问题标题】:Django pagination query duplicated, double the timeDjango分页查询重复,时间加倍
【发布时间】:2019-04-29 18:45:40
【问题描述】:

在我当前的项目中,我想对查询集进行一些过滤和排序,并以分页形式向用户显示。
这很好用,但是我对性能感到不舒服。
当我在模型元排序中显式或隐式使用 and order_by 语句时,我可以在“调试”工具栏中看到该查询实际上被执行了两次。
一次用于分页器计数(没有 ORDER BY),一次用于获取对象切片(使用 ORDER BY)。
根据我的观察,这导致所需时间加倍。

有什么办法可以优化吗?

下面是一个最小的工作示例,在我的实际应用中,我使用基于类的视图。

class Medium(models.Model):
    title = models.CharField(verbose_name=_('title'),
                             max_length=256,
                             null=False, blank=False,
                             db_index=True,
                             )
    offered_by = models.ForeignKey(Institution,
                                   verbose_name=_('Offered by'),
                                   on_delete=models.CASCADE,
                                   )
    quantity = models.IntegerField(verbose_name=_('Quantity'),
                                   validators=[
                                       MinValueValidator(0)
                                   ],
                                   null=False, blank=False,
                                   )
    deleted = models.BooleanField(verbose_name=_('Deleted'),
                                  default=False,
                                  )

def index3(request):
    media = Medium.objects.filter(deleted=False, quantity__gte=0)
    media = media.exclude(offered_by_id=request.user.institution_id)
    media = media.filter(title__icontains="funktion")
    media = media.order_by('title')
    paginator = Paginator(media, 25)
    media = paginator.page(1)
    return render(request, 'media/empty2.html', {'media': media})

Debug toolbar sql timings

【问题讨论】:

    标签: django pagination query-optimization django-queryset


    【解决方案1】:

    查询不完全重复:一个是COUNT 查询,另一个是获取请求的特定页面的实际对象。这是不可避免的,因为 Django 的 Paginator 需要知道对象的总数。但是,如果查询集media 不是太大,您可以通过强制评估media 查询集来优化(只需在定义分页器之前添加一行len(media))。

    但请注意,如果 media 非常大,您可能不想在将所有对象加载到内存时强制评估 media

    【讨论】:

    • 不幸的是,强制对查询集进行评估不是一种选择。我只是好奇是否可以进行任何其他优化,因为我注意到COUNT 查询缺少ORDER_BY。如果我省略.order_by(),第二个查询执行得更快。但我现在想,这完全有道理。
    • 那么除了接受两个查询之外别无他法。你需要结果/页面的总数,这是不可避免的。
    猜你喜欢
    • 2012-04-19
    • 1970-01-01
    • 1970-01-01
    • 2016-05-27
    • 2012-06-07
    • 1970-01-01
    • 1970-01-01
    • 2018-05-07
    • 2012-08-27
    相关资源
    最近更新 更多