Django Paginate CPU时间缩放与所选对象的数量不显示对象

时间:2010-11-01 18:49:59

标签: python django django-pagination

我有一个包含大约3900个条目的简单数据库,并且使用通用视图(django.views.generic.list_detail.object_list)及其django-pagination(通过paginate_by)来浏览数据库中的数据,但是有些查询很慢。

奇怪的是,尽管每页只显示50个对象,但渲染时间与选择了多少个对象大致呈线性关系(并且我不对对象进行任何排序)。例如,如果我用~3900,~1800,~900,~54个选定对象进行查询,它分别需要~8500 ms,~4000 ms,~2500 ms,~800 ms的CPU时间(使用django-debug-toolbar)虽然SQL只花了大约50毫秒,大约40毫秒,大约35毫秒,大约30毫秒,而所有页面只有50个对象。我已根据django optimization page中的建议使用select_related最小化了SQL查询的数量。

使用profiling middleware绝大部分时间用于长查询都花费在db中:

         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和free说只使用300Mb正在使用(另外600Mb缓存)),数据库与机器在同一台服务器上。

发现我的错误。我发现了自己的错误。我检查了原始查询集的长度,看它是否为长度1(如果是的话,然后转到object_detail)。这导致评估完整的查询集(根据django-debug-toolbar仍然只花了5ms),但显着减慢了一切。

基本上有一些愚蠢的东西:

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

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

1 个答案:

答案 0 :(得分:3)

当django进行分页时,它将使用标准的QuerySet切片来获取结果,这意味着它将使用LIMITOFFSET

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

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

然后,您可以向sqlite询问EXPLAIN查询,并查看数据库正在尝试执行的操作。我猜你正在排序一些没有索引的字段。根据{{​​3}}的sqlite文档,EXPLAIN QUERY PLAN会告诉你哪些索引会被使用