在Django视图中保持状态以提高分页性能

时间:2015-10-05 23:29:14

标签: python django postgresql datatables

我正在设计一个data-tables驱动的Django应用程序,并且有一个data-tables调用AJAX的API视图(我在服务器端处理模式下使用data-tables)。它实现搜索,分页和排序。

我的数据库最近变得很大(大约500,000个条目)并且性能极大地受到影响,无论是搜索还是简单地移动到下一页。我怀疑我写这个观点的方式非常低效。这是我在视图中所做的(假设我的数据库中的对象是比萨饼):

  • filtered = Pizza.objects.filter(...)获取符合搜索条件的比萨饼。 (如果没有搜索条件,则为Pizza.objects.all()。)

  • paginated = filtered[start: start + length]只获取当前的比萨饼页面。 (最多只有100个)。根据用户所在的页面,从data-tables客户端代码传入开始和长度。

  • pizzas = paginated.order_by(...)将订购应用于当前页面。

然后我将pizzas转换为JSON并从视图中返回它们。

似乎虽然搜索可能是对500,000个条目的缓慢操作,但只是移动到下一页不应该要求我们重做整个搜索。所以我想要做的就是在视图中缓存一些东西(这是一个基于类的视图)。我会跟踪最后一个搜索字符串是什么,以及它产生的结果集。

然后,如果请求通过并且搜索字符串没有不同(如果用户点击几页结果会发生这种情况)我不必再次访问数据库以获取过滤结果 - 我可以使用缓存版本。

这是一个只读应用程序,因此不同步不会成为问题。

我甚至可以保存一大堆搜索字符串和他们应该制作的比萨饼。

我想知道的是:这是解决问题的合理方法吗?或者我有什么东西可以俯瞰?另外,我在这里重新发明了轮子吗?并不是说这不容易实现,但是QuerySet上有内置选项还是要做什么?

2 个答案:

答案 0 :(得分:2)

pizzas = paginated.order_by(...)很慢,它排序所有Pizzas而不是当前页面。索引帮助:https://docs.djangoproject.com/en/1.8/topics/db/optimization/#use-standard-db-optimization-techniques

如果您真的想要缓存,请结帐https://github.com/Suor/django-cacheops,"支持自动或手动查询集缓存以及自动粒度事件驱动失效的灵活应用。"

答案 1 :(得分:1)

有多种方法可以改善您的代码结构,

首先,您只使用Django ORM命中根据您的页码获取所需的数据,其次是您缓存ORM输出并重新使用该结果,如果再次传递相同的查询。

首先是这样。

在您的代码中

Pizza.objects.all() paginated = filtered[start: start + length] 您首先获取所有数据然后,您正在切片,这是非常昂贵的SQL查询,将其转换为

filtered = Pizza.objects.all()[(page_number-1) * 30, (page_number-1) * 30 + 30]

以上给定的ORM只会获取那些根据提供的页码的行,并且与获取所有行然后切片相比非常快。

第二种方式,首先是根据查询提取数据,缓存解决方案,如memcache或redis,下次当你需要从数据库中获取数据时,先检查如果该查询的缓存中存在数据(如果存在),则只需使用该数据,因为内存缓存解决方案比从数据库中获取数据更快,因为内存和硬盘之间的输入输出传输非常大,我们知道硬盘传统上很慢。