2009-07-23 73 views
5

我正在比較我的舊PHP腳本與更新的Django版本和PHP版本,全部吐出HTML並且所有功能都運行得更快。 Django上的某些東西必須是錯誤的地方要快得多。Django(?)在執行一些python分析之後真的很慢,數據集很大

首先,一些上下文:我有一個頁面,吐出銷售數據的報告。數據可以被許多事物過濾,但大部分都是按日期過濾的。這使得緩存它有點難,因爲結果的可能性幾乎是無窮無盡的。有很多數字和計算都完成了,但在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是什麼,因爲我沒有在自己的代碼中執行任何正則表達式或類似的東西(Something Django正在做什麼?)最接近的是我正在使用itertools ifilter。

看來這些是主要的罪魁禍首,如果我能想出如何減少那些處理時間,那麼我會有一個更快的頁面。

有沒有人有任何建議,我可以開始減少?我真的不知道如何解決這個令牌/小數問題,而不是簡單地刪除它們。

更新:我在大多數數據上運行了一些帶/不帶過濾器的測試,並且結果時間幾乎相同,後者速度稍快但不是問題的原因。 tokenize.py究竟發生了什麼?

+0

如果沒有您的視圖代碼和分析指導,建議您不可能提供有用的信息。 – 2009-07-23 19:30:19

+0

亞歷克斯:我的觀點很簡單。它提取了一個初始條目列表,然後如果報告被修改,它會添加一些過濾器。這就是它。然後,我的模板將數據集重新分組爲兩部分,然後循環遍歷它,沿途調用模板標籤(但我已經將模板標籤的時間定在0.1 - > 0.5秒內執行。這些模板標籤是報告的小計/總計所以對於大量的數據來說執行時間是可以的。) – Bartek 2009-07-23 19:50:26

+0

@Bartek:請不要評論你自己的問題。這是你的問題,你可以更新它來包含所有相關的事實。 – 2009-07-23 20:04:43

回答

6

由於您沒有任何類型的代碼示例,因此有很多事情需要假設您的問題。

以下是我的假設:您正在使用Django的內置ORM工具和模型(即sales-data = modelobj.objects().all()),並且在PHP端處理直接SQL查詢和工作與一個query_set。

Django正在做大量的類型轉換和轉換爲從數據庫查詢到ORM/Model對象和關聯的管理器(默認情況下爲objects())的數據類型。

在PHP中你控制的轉換和確切地知道如何從一種數據類型轉換爲另一種,則是僅基於這個問題節省一些執行時間。

我會建議您嘗試一些花哨數量的工作轉移到數據庫中,特別是如果你正在做的,基於記錄集處理 - 數據庫吃早飯的那種處理。在Django中您可以通過發送原始的SQL數據庫:http://docs.djangoproject.com/en/dev/topics/db/sql/#topics-db-sql

我希望這至少可以讓你在正確的方向...

+0

謝謝。你是對的,這是有道理的。我看到查詢執行得很好,並且低MS,所以我從來沒有考慮過這個問題。這個問題當然是,ORM很可愛,並且在這樣的情況下保持代碼更加清潔,所以如果可能的話,我會喜歡不必沿着這條路走下去。我所做的數字處理並不複雜(添加這三個數字,然後乘以),然後使用| intcomma和| floatformat:2 django過濾器輸出它們,所以我不確定這是否是問題的核心。 – Bartek 2009-07-23 19:45:18

+0

您可能遇到的有關添加號碼的問題,乘以號碼是記錄的數量。如果您保持較低的返回記錄數量,它將減少內存開銷以及處理該數據所花費的時間。記住這一點:你不能更快地創建應用程序,你只能讓它做更少的工作。 – 2009-07-23 19:54:28

+0

不幸的是,在一些嚴重的情況下,用戶想要一份年度銷售數據報告,而且我無法保持較低的記錄。 .. :) – Bartek 2009-07-23 19:55:47

2

「tokenize.py出來放在上面,它可以使一些因爲我正在做很多數字格式化。「

根本沒有意義。

請參閱http://docs.python.org/library/tokenize.html

的令牌化模塊提供了一個詞彙 掃描儀Python源代碼, 在Python

記號化實施現身頂部意味着你有動態代碼解析回事。

AFAIK(在Django存儲庫上執行搜索)Django不使用標記化。這樣就會讓程序執行某種動態代碼實例化。或者,您只是簡單地分析第一個時間,程序被加載,解析並運行,導致對時間正在進行的錯誤假設。

你應該礙着計算模板標籤 - 它的速度慢。它涉及模板標籤的複雜元評估。你應該在簡單,低開銷的Python中在視圖中進行所有計算。僅將模板用於演示文稿。

此外,如果您經常查詢,過濾器和以及什麼,而不是,你有一個數據倉庫。獲取有關數據倉庫設計的書籍,並遵循數據倉庫設計模式。

您必須有一箇中心事實表,由維度表包圍。這非常非常有效。

和的,分組依據等,都可以作爲在Python defaultdict操作來完成。批量獲取所有行,以期望的結果構建字典。如果這太慢了,那麼你必須使用數據倉庫技術來保存與你的細粒度事實分開的持久性總和和組。通常這涉及跨越Django ORM並使用RDBMS功能,如派生數據的視圖或表。

+0

你能告訴我爲什麼我不應該在templatetags中做任何計算(基本除了總結數字)嗎?在你的帖子後,我想出了一種更有效的方式來做我的模板標籤正在做的事,這是有用的,但它們仍然不是瓶頸。至少它會剃掉幾秒鐘的處理時間:) 謝謝 – Bartek 2009-07-24 02:05:37

2

當處理大量數據時,通過使用ValuesQuerySet可以更直接地訪問查詢結果,而不是爲結果中的每一行創建模型對象實例,還可以節省大量CPU和內存。

它的使用看起來有點像這樣:

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

在這種情況下數據庫往往是瓶頸。另外,使用ORM可能會導致次優SQL查詢。

正如一些人指出的那樣,無法分辨探頭的真實性,只是提供您提供的信息。

我可以給你一些一般性的建議:

  • 如果你的觀點正在與相關的模型對象,可以考慮使用select_related()。這種簡單的方法可能會大大加快ORM生成的查詢速度。
  • 使用Debug Footer Middleware可查看視圖生成的SQL查詢以及它們執行的時間。

PS:只是,我曾經有一個相當簡單的視圖,它非常緩慢。安裝Debug Footer Middleware後,我看到了500左右! SQL查詢在該單一視圖中執行。只需使用select_related()就可以將該查詢帶入5個查詢,並按預期方式執行視圖。