Django(?)在进行一些python性能分析后,对于大型数据集确实很慢

时间:2009-07-23 18:58:10

标签: python django optimization

我正在比较我的一个旧的PHP脚本与较新的,更高级的Django版本和PHP版本,完全吐出HTML并且所有功能都运行得更快。更快到Django上的某些东西必须出错。

首先,一些背景信息:我有一个页面可以显示销售数据的报告。数据可以通过许多方式进行过滤,但大部分都是按日期过滤的。这使得缓存它有点困难,因为结果的可能性几乎是无穷无尽的。有很多数字和计算已完成,但在PHP中处理它并不是一个很大的问题。

更新

  • 经过一些额外的测试后,我的视图中没有任何内容导致减速。如果我只是对数据进行数字处理并吐出5行渲染的HTML,那就不那么慢(仍然比PHP慢),但如果我渲染了大量数据,那就非常慢了。

  • 每当我运行大型报告(例如当年的所有销售)时,机器的CPU使用率都会达到100%。不知道这是否意味着什么。我正在使用mod_python和Apache。也许转换到WSGI可能会有所帮助吗?

  • 我的模板标签显示小计/总计处理的时间从0.1秒到1秒,适用于非常大的集合。我在报告中称他们为6次,所以他们似乎不是最大的问题。

现在,我运行了一个Python分析器并返回了这些结果:

Ordered by: internal time
   List reduced from 3074 to 20 due to restriction 

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
  2939417   26.290    0.000   44.857    0.000 /usr/lib/python2.5/tokenize.py:212(generate_tokens)
  2822655   17.049    0.000   17.049    0.000 {built-in method match}
  1689928   15.418    0.000   23.297    0.000 /usr/lib/python2.5/decimal.py:515(__new__)
 12289605   11.464    0.000   11.464    0.000 {isinstance}
   882618    9.614    0.000   25.518    0.000 /usr/lib/python2.5/decimal.py:1447(_fix)
    17393    8.742    0.001   60.798    0.003 /usr/lib/python2.5/tokenize.py:158(tokenize_loop)
       11    7.886    0.717    7.886    0.717 {method 'accept' of '_socket.socket' objects}
   365577    7.854    0.000   30.233    0.000 /usr/lib/python2.5/decimal.py:954(__add__)
  2922024    7.199    0.000    7.199    0.000 /usr/lib/python2.5/inspect.py:571(tokeneater)
   438750    5.868    0.000   31.033    0.000 /usr/lib/python2.5/decimal.py:1064(__mul__)
    60799    5.666    0.000    9.377    0.000 /usr/lib/python2.5/site-packages/django/db/models/base.py:241(__init__)
    17393    4.734    0.000    4.734    0.000 {method 'query' of '_mysql.connection' objects}
  1124348    4.631    0.000    8.469    0.000 /usr/lib/python2.5/site-packages/django/utils/encoding.py:44(force_unicode)
   219076    4.139    0.000  156.618    0.001 /usr/lib/python2.5/site-packages/django/template/__init__.py:700(_resolve_lookup)
  1074478    3.690    0.000   11.096    0.000 /usr/lib/python2.5/decimal.py:5065(_convert_other)
  2973281    3.424    0.000    3.424    0.000 /usr/lib/python2.5/decimal.py:718(__nonzero__)
   759014    2.962    0.000    3.371    0.000 /usr/lib/python2.5/decimal.py:4675(__init__)
   381756    2.806    0.000  128.447    0.000 /usr/lib/python2.5/site-packages/django/db/models/fields/related.py:231(__get__)
   842130    2.764    0.000    3.557    0.000 /usr/lib/python2.5/decimal.py:3339(_dec_from_triple)

tokenize.py出现在顶部,这可以说明一点,因为我正在进行大量的数字格式化。 Decimal.py很有意义,因为报告基本上是90%的数字。我不知道内置方法match是什么,因为我没有在我自己的代码中做任何正则表达式或类似的东西(Django正在做什么?)最接近的是我使用的是itertools ifilter。

这似乎是主要的罪魁祸首,如果我能弄清楚如何减少那些处理时间,那么我会有一个更快的页面。

有没有人对如何开始减少这个有任何建议?我真的不知道如何解决这个令牌化/小数问题,而不是简单地删除它们。

更新:我在大多数数据上运行了一些带/不带过滤器的测试,结果时间几乎相同,后者速度稍快但不是问题的原因。 tokenize.py到底发生了什么?

4 个答案:

答案 0 :(得分:6)

由于您没有任何类型的代码示例,因此有很多事情要考虑您的问题。

以下是我的假设:您正在使用Django的内置ORM工具和模型(即sales-data = modelobj.objects()。all()),在PHP方面,您正在处理直接SQL查询和使用一个query_set。

Django正在进行大量的类型转换和转换,数据类型从数据库查询到ORM / Model对象和关联的管理器(默认情况下为objects())。

在PHP中,您控制转换并确切知道如何从一种数据类型转换为另一种数据类型,您只需基于该问题节省一些执行时间。

我建议尝试将一些奇特的数字工作移到数据库中,特别是如果你正在进行基于记录集的处理 - 数据库从早餐中吃掉那种处理方式。在Django中,您可以将RAW SQL发送到数据库:http://docs.djangoproject.com/en/dev/topics/db/sql/#topics-db-sql

我希望这至少可以让你指出正确的方向......

答案 1 :(得分:2)

“tokenize.py出现在最顶层,这可以说明我正在进行大量的数字格式化。”

毫无意义。

请参阅http://docs.python.org/library/tokenize.html

  

tokenize模块提供了一个词法   用于Python源代码的扫描程序,   用Python实现

Tokenize名列前茅意味着您正在进行动态代码解析。

AFAIK(在Django存储库上搜索)Django不使用tokenize。这样就可以让你的程序进行某种动态代码实例化。或者,您只是分析程序加载,解析和运行的第一个时间,导致对时间的错误假设。

你应该在模板标签中进行计算 - 这很慢。它涉及模板标签的复杂元评估。您应该在简单,低开销的Python中在视图中进行所有计算。使用模板仅用于演示。

此外,如果您经常进行查询,过滤,总结以及什么不是,那么您就拥有了一个数据仓库。获取有关数据仓库设计的书籍,并遵循数据仓库设计模式。

您必须有一个中心事实表,由维度表包围。这非常非常有效。

Sums,group bys等可以在Python中作为defaultdict操作完成。批量获取所有行,使用所需结果构建字典。如果这太慢了,那么你必须使用数据仓库技术来保存持久的总和和你的细粒度事实。这通常涉及走出Django ORM并使用RDBMS功能,如视图或派生数据表。

答案 2 :(得分:2)

在处理大量数据时,您还可以使用更直接访问查询结果的ValuesQuerySet来节省大量CPU和内存,而不是为结果中的每一行创建模型对象实例。

它的用法看起来有点像这样:

Blog.objects.order_by('id').values()

答案 3 :(得分:1)

在这种情况下,数据库通常是瓶颈。此外,使用ORM可能会导致次优的SQL查询。

正如一些人所指出的那样,只能根据你提供的信息来判断探测器究竟是什么。

我可以给你一些一般的建议:

  • 如果您的视图使用相关模型对象,请考虑使用select_related()。这种简单的方法可以大大加快ORM生成的查询速度。
  • 使用Debug Footer Middleware查看视图生成的SQL查询以及执行时间。
PS:只是fyi,我曾经有一个相当简单的观点,这个观点很慢。安装Debug Footer Middleware后,我看到了大约500个! sql查询在该单个视图中执行。只需使用select_related()即可将该问题降至5个查询,并按预期执行视图。