我正在设计一个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
上有内置选项还是要做什么?
答案 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,下次当你需要从数据库中获取数据时,先检查如果该查询的缓存中存在数据(如果存在),则只需使用该数据,因为内存缓存解决方案比从数据库中获取数据更快,因为内存和硬盘之间的输入输出传输非常大,我们知道硬盘传统上很慢。