我正在设计一个data-tables
驱动的Django应用程序,并且有一个用AJAX调用的API视图(我在服务器端处理模式中使用data-tables
)。它实现搜索、分页和排序。在
我的数据库最近变得很大(大约500000个条目),性能受到很大影响,无论是搜索还是简单地移动到下一个页面。我怀疑我写这个观点的方式非常低效。下面是我在视图中的操作(假设数据库中的对象是pizza):
filtered = Pizza.objects.filter(...)
以获取与搜索条件匹配的比萨饼集。(或者Pizza.objects.all()
,如果没有搜索条件)。
paginated = filtered[start: start + length]
只获取当前页面的比萨饼。(最多只有100个)。{根据客户端}的长度,{1从客户端开始传递}。
pizzas = paginated.order_by(...)
将排序应用于当前页。
然后我将pizzas
转换为JSON并从视图中返回它们。在
看起来,虽然搜索对500000个条目可能是一个缓慢的操作,但是仅仅移动到下一个页面不应该要求我们重做整个搜索。所以我想做的是在视图中缓存一些东西(这是一个基于类的视图)。我会跟踪上一个搜索字符串是什么,以及它产生的结果集。在
然后,如果一个请求通过并且搜索字符串没有变化(如果用户点击几页结果就会发生这种情况),我就不必再次访问数据库来获得过滤的结果——我可以使用缓存的版本。在
它是一个只读的应用程序,所以不同步不是问题。在
我甚至可以保存一本字典,里面有一大堆搜索字符串和他们应该制作的比萨饼。在
我想知道的是:这是解决问题的合理方法吗?还是我忽略了什么?还有,我是不是在重新发明轮子?这并不是说这不容易实现,而是在QuerySet
上有一个内置的选项或其他方法来实现吗?在
有多种方法可以改善代码结构
第一种方法是使用Django ORM hit只获取根据页码所需的数据,第二种方法是缓存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,下次需要从数据库中取数据时,先检查该查询的缓存中是否有数据,如果有,则直接使用该数据,因为内存缓存解决方案比从数据库中获取数据要快得多,因为内存和硬盘之间的输入输出传输非常大,而且我们知道传统上硬盘的速度很慢。在
pizzas = paginated.order_by(...)
速度很慢,它对所有比萨饼进行排序,而不是对当前页面进行排序。索引帮助:https://docs.djangoproject.com/en/1.8/topics/db/optimization/#use-standard-db-optimization-techniques如果你真的想要缓存,签出https://github.com/Suor/django-cacheops,“一个灵活的应用,支持自动或手动查询集缓存和自动粒度事件驱动的失效。”
相关问题 更多 >
编程相关推荐