Python Django使用选定对象数(未显示对象数)分页CPU时间缩放

Python Django使用选定对象数(未显示对象数)分页CPU时间缩放,python,django,django-pagination,Python,Django,Django Pagination,我有一个大约3900个条目的简单数据库,我使用一个通用视图(django.views.generic.list_detail.object_list)及其django分页(通过paginate_by)来浏览数据库中的数据,但有些查询非常慢 奇怪的是,尽管每页只显示50个对象,但渲染时间与所选对象的数量大致呈线性关系(我没有对对象进行任何排序)。例如,如果我使用~3900、~1800、~900、~54个选定对象进行查询,则分别需要~8500毫秒、~4000毫秒、~2500毫秒、~800毫秒的CPU

我有一个大约3900个条目的简单数据库,我使用一个通用视图(django.views.generic.list_detail.object_list)及其django分页(通过paginate_by)来浏览数据库中的数据,但有些查询非常慢

奇怪的是,尽管每页只显示50个对象,但渲染时间与所选对象的数量大致呈线性关系(我没有对对象进行任何排序)。例如,如果我使用~3900、~1800、~900、~54个选定对象进行查询,则分别需要~8500毫秒、~4000毫秒、~2500毫秒、~800毫秒的CPU时间(使用django debug工具栏),而SQL只需要~50毫秒、~40毫秒、~35毫秒、~30毫秒,而所有页面都只有50个对象。我已经按照中的建议,使用select_related最小化了SQL查询的数量

在长查询上使用的绝大多数时间都花在了数据库上:

         735924 function calls (702255 primitive calls) in 11.950 CPU seconds

   Ordered by: internal time, call count

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
35546/3976    4.118    0.000    9.585    0.002 /usr/local/lib/python2.6/dist-packages/django/db/models/query.py:1120(get_cached_row)
    30174    3.589    0.000    3.991    0.000 /usr/local/lib/python2.6/dist-packages/django/db/models/base.py:250(__init__)

 ---- By file ----

      tottime
47.0%   3.669 /usr/local/lib/python2.6/dist-packages/django/db/models/base.py
 7.7%   0.601 /usr/local/lib/python2.6/dist-packages/django/db/models/options.py
 6.8%   0.531 /usr/local/lib/python2.6/dist-packages/django/db/models/query_utils.py
 6.6%   0.519 /usr/local/lib/python2.6/dist-packages/django/db/backends/sqlite3/base.py
 6.4%   0.496 /usr/local/lib/python2.6/dist-packages/django/db/models/sql/compiler.py
 5.0%   0.387 /usr/local/lib/python2.6/dist-packages/django/db/models/fields/__init__.py
 3.1%   0.244 /usr/local/lib/python2.6/dist-packages/django/db/backends/util.py
 2.9%   0.225 /usr/local/lib/python2.6/dist-packages/django/db/backends/__init__.py
 2.7%   0.213 /usr/local/lib/python2.6/dist-packages/django/db/models/query.py
 2.2%   0.171 /usr/local/lib/python2.6/dist-packages/django/dispatch/dispatcher.py
 1.7%   0.136 /usr/local/lib/python2.6/dist-packages/django/template/__init__.py
 1.7%   0.131 /usr/local/lib/python2.6/dist-packages/django/utils/datastructures.py
 1.1%   0.088 /usr/lib/python2.6/posixpath.py
 0.8%   0.066 /usr/local/lib/python2.6/dist-packages/django/db/utils.py
...
 ---- By group ---

      tottime
89.5%   6.988 /usr/local/lib/python2.6/dist-packages/django/db
 3.6%   0.279 /usr/local/lib/python2.6/dist-packages/django/utils
...
我可以理解为什么SQL查询可以随所选条目的数量而扩展。然而,我不明白为什么剩余的CPU时间会受到影响。这是非常违反直觉的,我想知道是否有人可以帮助我调试/分析技巧

将django-1.2.3与sqlite、python2.6、apache2 prefork一起使用(尽管切换到mpm worker并没有显著改变)。如有任何提示/窍门,将不胜感激。内存使用似乎也不是一个因素(机器有2Gb的RAM,空闲时仅使用300Mb的内存(另外还有600Mb的缓存)),数据库与机器位于同一台服务器上

发现了我的错误。我发现了我的错误。我检查了原始查询集的长度,看它是否为长度1(如果是,则转到object_detail)。这导致了对完整queryset的评估(根据django调试工具栏,这仍然只需要5毫秒),但大大降低了速度

基本上有一些愚蠢的事情,比如:

    if len(queryset) == 1:                                 
        return HttpResponseRedirect( fwd to object_detail url ...)
    return object_list(request, queryset=queryset, paginate_by=  ...)

它评估了完整的查询;不是分页查询。

当django进行分页时,它将使用标准QuerySet切片来获得结果,这意味着它将使用
限制
偏移

您可以通过调用QuerySet的
.query
属性上的
str()
来查看ORM生成的SQL:

    print MyModel.objects.all().query
    print MyModel.objects.all()[50:100].query

然后,您可以要求sqlite解释查询,并查看数据库试图做什么。我猜您是在某个没有索引的字段上排序<代码>解释查询计划将告诉您将使用哪些索引,根据sqlite文档中的

您在sqlite数据库中设置了索引吗?否则sqlite可能会进行线性扫描以进行筛选或排序;但是我也没有对结果进行排序,而且我的印象是django调试工具栏会对SQL查询进行计时。因此,如果选择3900个对象中的1-50个对象时SQL查询的总时间为50毫秒,选择54个对象中的1-50个对象时SQL查询的总时间为30毫秒,则CPU时间的差异应仅为20毫秒,而不是当前的7800毫秒。这很有帮助,并引导我沿着正确的轨道阅读SQL查询(在上面编辑的问题中解释)。如果您想了解有关何时计算查询的详细信息,请参阅,您可以尝试使用QuerySet…count()而不是len()。