2009-07-23 34 views
5

Tôi đã so sánh một tập lệnh PHP cũ của tôi so với phiên bản Django mới hơn và mới hơn, với phiên bản PHP đầy đủ và tất cả đều hoạt động nhanh hơn. MUCH nhanh hơn đến mức mà một cái gì đó đã được sai trên một Django.Django (?) Thực sự chậm với các tập dữ liệu lớn sau khi thực hiện một số hồ sơ python

Đầu tiên, một số ngữ cảnh: Tôi có một trang báo cáo các báo cáo về dữ liệu bán hàng. Dữ liệu có thể được lọc theo một số thứ nhưng chủ yếu được lọc theo ngày tháng. Điều này làm cho nó một chút khó khăn để cache nó như là khả năng cho kết quả là gần như vô tận. Có rất nhiều con số và tính toán được thực hiện nhưng nó không bao giờ là một vấn đề để xử lý trong PHP.

CẬP NHẬT:

  • Sau một số thử nghiệm bổ sung không có gì trong quan điểm của tôi đó gây ra sự suy giảm là. Nếu tôi chỉ đơn giản là số-crunching dữ liệu và phun ra 5 hàng của HTML rendered, nó không phải là chậm (vẫn còn chậm hơn so với PHP), nhưng nếu tôi vẽ rất nhiều dữ liệu, nó rất chậm.

  • Bất cứ khi nào tôi chạy báo cáo lớn (ví dụ: tất cả doanh số bán hàng trong năm), mức sử dụng CPU của máy sẽ đạt 100%. Không biết nếu điều này có nghĩa là nhiều. Tôi đang sử dụng mod_python và Apache. Có lẽ việc chuyển sang WSGI có thể giúp ích gì?

  • Thẻ mẫu của tôi hiển thị tổng phụ/tổng số quá trình từ 0,1 giây đến 1 giây cho các tập rất lớn. Tôi gọi cho họ khoảng 6 lần trong báo cáo để họ có vẻ không phải là vấn đề lớn nhất.

Bây giờ, tôi chạy một profiler Python và đã trở lại với những kết quả này:

 
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 đi ra trên đầu trang, có thể làm cho một số cảm giác như tôi đang làm rất nhiều định dạng số . Decimal.py có ý nghĩa vì báo cáo về cơ bản là 90% số. Tôi không có đầu mối những gì được xây dựng trong phương pháp match là như tôi không làm bất kỳ Regex hoặc tương tự trong mã của riêng tôi (Something Django đang làm gì?) Điều gần nhất là tôi đang sử dụng itertools ifilter.

Có vẻ như đó là những thủ phạm chính và nếu tôi có thể tìm ra cách để giảm thời gian xử lý của những người đó thì tôi sẽ có một trang nhanh hơn rất nhiều.

Có ai có bất kỳ đề xuất nào về cách tôi có thể bắt đầu giảm số này không? Tôi không thực sự biết làm thế nào tôi sẽ sửa lỗi này các vấn đề tokenize/thập phân mà không cần loại bỏ chúng.

Cập nhật: Tôi chạy một số thử nghiệm có/không có bộ lọc trên hầu hết dữ liệu và thời gian kết quả khá nhiều trở lại giống nhau, sau này nhanh hơn một chút nhưng không nhiều là nguyên nhân của vấn đề. Điều gì là chính xác xảy ra trong tokenize.py?

+0

Không thể đề xuất điều gì đó hữu ích nếu không có mã xem và hướng dẫn lược tả của bạn. –

+0

Alex: Quan điểm của tôi khá đơn giản. Nó kéo lên danh sách các mục nhập ban đầu, sau đó nếu báo cáo được sửa đổi, nó sẽ thêm một số bộ lọc. Đó thực sự là nó. Mẫu của tôi sau đó tập hợp lại các tập dữ liệu thành hai phần và sau đó lặp qua tất cả, gọi templatetags trên đường đi (Nhưng tôi đã hẹn giờ các thẻ mẫu để thực hiện trong 0,1 -> 0,5 giây .. các templatetags là tổng phụ/tổng của báo cáo do đó thời gian thực hiện là ok trên bộ dữ liệu khổng lồ.) – Bartek

+0

@Bartek: Vui lòng không bình luận về câu hỏi của riêng bạn. Đó là câu hỏi của bạn, bạn có thể cập nhật nó để chứa tất cả các sự kiện có liên quan. –

Trả lời

6

Có rất nhiều điều để giả định về vấn đề của bạn vì bạn không có bất kỳ loại mẫu mã nào. Dưới đây là những giả định của tôi: Bạn đang sử dụng các công cụ và mô hình ORM tích hợp của Django (ví dụ: sales-data = modelobj.objects(). All()) và bên PHP bạn đang xử lý các truy vấn SQL trực tiếp và làm việc với query_set.

Django đang thực hiện nhiều kiểu chuyển đổi và truyền sang kiểu dữ liệu từ truy vấn cơ sở dữ liệu sang đối tượng ORM/Model và trình quản lý liên quan (đối tượng() theo mặc định).

Trong PHP bạn đang kiểm soát chuyển đổi và biết chính xác cách truyền từ một kiểu dữ liệu này sang loại dữ liệu khác, bạn sẽ tiết kiệm được một số thời gian thực hiện dựa trên vấn đề đó.

Tôi khuyên bạn nên di chuyển một số công việc số ưa thích vào cơ sở dữ liệu, đặc biệt nếu bạn đang thực hiện xử lý dựa trên bản ghi - cơ sở dữ liệu sẽ ăn loại đó từ bữa sáng. Trong Django bạn có thể gửi RAW SQL trên cơ sở dữ liệu: http://docs.djangoproject.com/en/dev/topics/db/sql/#topics-db-sql

Tôi hy vọng điều này ít nhất có thể giúp bạn có được chỉ trong đúng hướng ...

+0

Cảm ơn. Bạn nói đúng, điều đó có ý nghĩa. Tôi đã nhìn thấy các truy vấn thực hiện tốt và với MS thấp vì vậy tôi không bao giờ xem xét điều đó. Vấn đề là tất nhiên, rằng ORM là đáng yêu và giữ mã sạch hơn trong các trường hợp như thế này vì vậy tôi sẽ tận hưởng không phải đi xuống con đường đó nếu có thể. Việc xử lý số tôi đang làm là không phức tạp (Thêm ba số, nhân này) và sau đó tôi chỉ đơn giản là xuất chúng bằng cách sử dụng | intcomma và | floatformat: 2 django bộ lọc vì vậy tôi không chắc chắn nếu đó là cốt lõi của vấn đề. – Bartek

+0

Sự cố bạn có thể gặp phải liên quan đến việc thêm số, nhân số là số lượng bản ghi. Nếu bạn giữ số bản ghi được trả lại thấp hơn, nó sẽ giảm chi phí bộ nhớ và lượng thời gian cần để xử lý dữ liệu đó. Lưu ý điều này: bạn không thể làm cho một ứng dụng nhanh hơn, bạn chỉ có thể làm cho nó hoạt động ít hơn. –

+0

Thật không may trong một số trường hợp nghiêm trọng, người dùng muốn có báo cáo dữ liệu bán hàng hàng năm và tôi thực sự không thể giữ hồ sơ thấp hơn. .. :) – Bartek

2

"tokenize.py đi ra trên đầu trang, có thể làm cho một số có nghĩa là tôi đang làm rất nhiều định dạng số. "

Không có ý nghĩa gì cả.

Xem http://docs.python.org/library/tokenize.html.

Module tokenize cung cấp một máy quét từ vựng cho mã nguồn Python, thực hiện bằng Python

tokenize sắp ra trên đầu có nghĩa là bạn có mã động phân tích xảy ra.

AFAIK (thực hiện tìm kiếm trên kho Django) Django không sử dụng mã thông báo. Vì vậy, để chương trình của bạn làm một số loại mã động. Hoặc, bạn chỉ định cấu hình lần đầu tiên khi chương trình của bạn được tải, phân tích cú pháp và chạy, dẫn đến giả định sai về thời gian sẽ diễn ra.

Bạn nên không bao giờ tính toán trong thẻ mẫu - quá chậm. Nó bao gồm một meta-đánh giá phức tạp của thẻ mẫu. Bạn nên thực hiện tất cả các phép tính trong khung nhìn bằng Python đơn giản, chi phí thấp. Chỉ sử dụng các mẫu cho bản trình bày.

Ngoài ra, nếu bạn liên tục thực hiện các truy vấn, bộ lọc, khoản tiền và điều gì không, bạn có kho dữ liệu. Nhận một cuốn sách về thiết kế kho dữ liệu và theo dõi các mẫu thiết kế kho dữ liệu.

Bạn phải có bảng thông tin trung tâm, được bao quanh bởi các bảng thứ nguyên. Điều này rất, rất hiệu quả.

Các khoản tiền, nhóm, vv, có thể được thực hiện dưới dạng hoạt động defaultdict bằng Python. Tải xuống hàng loạt tất cả các hàng, tạo từ điển với kết quả mong muốn. Nếu điều này quá chậm, thì bạn phải sử dụng kỹ thuật lưu trữ dữ liệu để lưu các khoản tiền liên tục và các nhóm riêng biệt với các sự kiện chi tiết của bạn. Thường thì điều này liên quan đến việc bước ra ngoài ORB của Django và sử dụng các tính năng của RDBMS như các khung nhìn hoặc các bảng dữ liệu có nguồn gốc.

+0

Bạn có thể cho tôi biết lý do tại sao tôi không nên thực hiện bất kỳ phép tính nào (bổ sung cơ bản để tổng hợp số) trong templatetags? Sau bài viết của bạn, tôi đã tìm ra một cách hiệu quả hơn để làm những gì templatetags của tôi đang làm mà là loại hữu ích nhưng họ vẫn không phải là nút cổ chai. Atleast nó sẽ cạo một vài giây thời gian xử lý :) Cảm ơn – Bartek

2

Khi xử lý nhiều tập dữ liệu, bạn cũng có thể tiết kiệm rất nhiều CPU và bộ nhớ bằng cách sử dụng ValuesQuerySet truy cập trực tiếp vào kết quả truy vấn thay vì tạo mẫu đối tượng mô hình cho mỗi hàng trong kết quả.

Đó là việc sử dụng trông hơi như thế này:

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

Trong một kịch bản như cơ sở dữ liệu thường là nút cổ chai. Ngoài ra, sử dụng ORM có thể dẫn đến các truy vấn SQL tối ưu phụ.

Như một số chỉ ra, không thể nói được xác suất thực sự là gì, chỉ với thông tin bạn cung cấp.

tôi chỉ có thể cung cấp cho bạn một số lời khuyên chung:

  • Nếu xem bạn đang làm việc với các đối tượng mô hình liên quan, xem xét sử dụng select_related(). Phương pháp đơn giản này có thể tăng tốc các truy vấn được tạo ra bởi ORM một cách đáng kể.
  • Sử dụng Debug Footer Middleware để xem truy vấn SQL nào được tạo bởi lượt xem của bạn và thời gian chúng thực hiện.

PS: Chỉ cần fyi, tôi đã từng có một cái nhìn khá đơn giản, rất chậm. Sau khi cài đặt Debug Footer Middleware tôi thấy rằng khoảng 500! truy vấn sql đã được thực thi trong chế độ xem duy nhất đó. Chỉ cần sử dụng select_related() đã mang đến 5 truy vấn và chế độ xem được thực hiện như mong đợi.

Các vấn đề liên quan