【发布时间】:2020-01-14 05:43:30
【问题描述】:
- 我的站点在从以下字段数据中过滤大行时遇到性能缓慢的问题。我在字段中存储的数据类型是
body字段中的RAW HTTP Response Body,其中包含大量内容,Project以下模型有 32k 个对象。
class Project(models.Model):
body = models.TextField(null=True,blank=True)
- 对
body执行过滤需要几秒钟。
>>> Project.objects.filter(body__icontains='x').count() ### 5-6 seconds
20472
我使用 Django 分页器对每个页面的数据进行切片。
>>> from django.core.paginator import Paginator
>>> data = Project.objects.filter(body__icontains='x')
>>> p = Paginator(data,10)
>>> p.page(1) ### takes 5-6 seconds here again because this function counts the total number of pages based on data.count()
<Page 1 of 2048>
- 然后我将分页器数据传递给模板,该模板只是循环并显示正文。
{% for each_data in data %}
{{ each_data.body }}
{% endfor %}
- 分页器的每一页都需要等待 5-6 秒,因为分页器函数对总数据集执行计数并返回页面范围。这是最大的缺点。
使用普通 Python 切片:
>>> data = Project.objects.filter(body__icontains='x')
>>> for each_data in data[0:10]: ### 0.1 seconds
print(each_data.body)
- 如您所见,如果我们根本不访问数据库,只是对数据进行切片并将其传递给模板,那么它将立即显示数据。
- 我相信当
Paginator函数计算我们每页过滤结果的总页数时,查询会变慢。 - 我相信分页器不适合大型数据集。
使用切片功能的缺点是:
- 我们无法计算过滤器返回的结果对象的总数。
- 看不到分页器应该有的页数,因为我们没有计算总数据集。
有没有什么办法可以解决这个问题,以便在分页的同时获得更快的结果?
【问题讨论】:
-
如果你想改进分页,你可以按照这个教程:medium.com/@hakibenita/…
-
我已经阅读了这篇文章,我相信我们可以不用分页本身,因为我们不计算返回的过滤对象总数,可以简单地使用
[offset:limit]来完成,但是,我正在寻找不损害count on returned objects或performance的解决方案 -
请注意,您的第二个示例使用了覆盖的
QuerySet.__getitem__()实现,它不会在之后对结果集进行切片,而是在生成的 SQL 查询中添加“offset”和“limit”子句。 -
虽然分页器发出的
count查询确实是开销的一部分,但根本问题是文本字段上的ilike %x%条件。您可能需要查看您的 RDBMS 手册以了解如何优化这一点(当然,如果可能的话)。
标签: django django-models