Django - 生产环境中特定视图的等待时间过长
我已经为这个问题纠结了至少两天。这个视图会生成一个页面,显示某个用户或电话分机拨打的所有电话。没什么特别的,就是一长页,最多1000行。
这个视图函数会从网址中接收一些参数,以决定在页面上显示什么。有两种情况,一种是网址中传入“extension=xxxxxx”,另一种是传入“user=xxxx”:
if request.GET.get("extension", None):
# extension_query expects only one Extension object
extension_query = Extension.objects.filter(number=request.GET["extension"])
... # Here I do some conditionals to match the right Extension object.
elif request.GET.get("user", None):
... # Simple stuff, nothing to significant.
# at the end I call render_to_response normally
编辑 - 这是调用我自定义的render_to_response的代码片段:
编辑2 - 在John C的建议下,我强制评估查询集后,加载时间从1.6分钟减少到14秒:现在我在将调用传递给自定义的render_to_response之前,将其转换为list():
if (request.GET.get("format", None) == "screen"
or request.GET.get("print", False)):
ctx = dict(calls=list(calls), client=client, extension=extension,
no_owner_extension=no_owner_extension,
start=start_date, end=end_date, tab="clients",
owner=user)
return finish_request(
request, "reports/exporting_by_call_type.html", ctx)
这是我自定义的render_to_response:
def finish_request(request, template, context):
if "print" in request.GET or "print" in request.POST:
context.update(printing=True)
return render_to_response(
template, RequestContext(request, context))
在我的开发机器上,根据Chrome的审计,处理这个视图在现实数据场景下需要3-4秒,适用于两种情况。在生产环境中,当网址中传入user参数时,加载视图也需要3-4秒,但当传入extension时,却需要2分钟!
编辑:需要说明的是,传入user或extension在网址中并不会改变最终渲染的页面,除了顶部的一行,我会指明这个分机号码属于谁。其余的数据完全一样。
我对生成这个视图的代码中的每个小块进行了性能分析。我测量了在我的生产代码中render_to_response的时间(0.05秒)。我删除了模板中调用extension的部分,但没有成功。我还使用了django_debug_toolbar来查看每条SQL语句的执行情况,最多查询也只需要2秒。
我还要补充的是,我在生产设置中使用mod_wsgi,debug=False...尽管加载时间需要2分钟,YSlow还是给这个页面打了94分。
有没有人能给点建议?
1 个回答
我觉得这段代码看起来没什么明显的问题。我有一个问题,你是希望正好匹配到 一个 对象吗?如果是这样,可以试试这段代码:
getData = request.GET.copy() # optional, I like my own copy.
if 'extension' in getData:
ext = getData['extension']
extObj = Extension.objects.get(number__exact=ext) # double-underline
# elif...
注意,这样会得到一个扩展 对象,而不是一个查询集。如果你有多个扩展,那就需要用 filter,不过我还是建议使用 exact,并且把从字典中读取 ext 的操作放到 filter 语句外面。
更新(根据我的评论) - 尝试强制立即评估查询集,使用 list() 来看看这对 render_to_response 有没有影响。
更新 2 - 既然 确实有影响 - 我觉得可能发生了什么。因为 Django 的查询集使用的是懒惰评估,当模板最终执行时,它调用的是一个迭代器,而不是一个现成的列表。也许函数调用太多了,每次调用迭代器获取新值时,都会产生很多不必要的开销。或者可能是个bug。:)