2015-10-05 46 views
1

表现我设计一个data-tables驱动的Django应用程序,并有data-tables电话与AJAX(我使用其服务器端处理模式data-tables)的API视图。它实现搜索,分页和排序。在Django视图状态保持改善分页

我的数据库最近变大了(大约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

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,“支持自动或手动查询集缓存和自动细粒度事件驱动失效的流畅应用程序。”

+0

哇,这是真的吗?如果我先切片查询集,然后做过滤/排序/无论它,它实际上是过滤/命令/任何然后切片? –

+0

根据django 1.8的文档,“对未评估的QuerySet进行切片会返回另一个未评估的QuerySet,因此不允许对其进行进一步修改(例如,添加更多过滤器或修改排序)”。所以看起来我部分错了,'pizzas = paginated.order_by(...)'是不允许的。仍然“考虑将索引添加到您经常使用filter(),exclude(),order_by()查询的字段” – JimmyYe

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会只获取那些根据提供的页码数的行,并且非常快速地获取所有行然后进行分片。

第二种方式,是根据查询端起上,像内存缓存或redis的,当你需要从数据库中获取数据下一次高速缓存解决方案,则首先检查数据是否存在首先获取数据在该查询的缓存中,如果存在,则只需使用该数据,因为内存缓存解决方案比从数据库获取数据要快得多,因为内存和硬盘驱动器之间的输入输出传输量非常大,而且我们知道传统上硬盘驱动器慢。