Вопрос по python, optimization, django – Django (?) Очень медленно работает с большими наборами данных после некоторого профилирования Python

5

Я сравнивал мой старый PHP-скрипт с более новой, более красивой версией Django и PHP, с полным выплевыванием из HTML, и все работало быстрее. Гораздо быстрее, до такой степени, что что-то должно быть не так с Джанго.

Сначала немного контекста: у меня есть страница, на которой выкладываются отчеты о продажах. Данные могут быть отфильтрованы по ряду вещей, но в основном фильтруются по дате. Это немного затрудняет кеширование, поскольку возможности для результатов практически безграничны. Было сделано много цифр и вычислений, но в PHP это никогда не было большой проблемой.

ОБНОВЛЕНИЕ:

After some additional testing there is nothing within my view that is causing the slowdown. If I am simply number-crunching the data and spitting out 5 rows of rendered HTML, it's not that slow (still slower than PHP), but if I am rendering a lot of data, it's VERY slow.

Whenever I ran a large report (e.g. all sales for the year), the CPU usage of the machine goes to 100%. Don't know if this means much. I am using mod_python and Apache. Perhaps switching to WSGI may help?

My template tags that show the subtotals/totals process anywhere from 0.1 seconds to 1 second for really large sets. I call them about 6 times within the report so they don't seem like the biggest issue.

Теперь я запустил профилировщик 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 как я не использую Regex или что-то подобное в своем собственном коде (что-то делает Django?). Самое близкое, что я использую itertools ifilter.

Похоже, это главные виновники, и если бы я мог понять, как сократить время их обработки, то у меня была бы намного более быстрая страница.

У кого-нибудь есть какие-либо предложения о том, как я мог бы начать сокращать это? Я на самом деле не знаю, как бы я решил эту проблему с токенизацией / десятичной разметкой, не просто удаляя их.

Обновление: я выполнил некоторые тесты с / без фильтров на большинстве данных, и результаты в целом вернулись к тому же результату, последний был немного быстрее, но не стал причиной проблемы. Что именно происходит в tokenize.py?

Невозможно предложить что-то полезное без вашего кода представления и руководства по профилированию. Alex Koshelev
@ Бартек: Пожалуйста, не комментируйте свой вопрос. Это ваш вопрос, вы можете обновить его, чтобы он содержал все соответствующие факты. S.Lott
Попробуйте извлечь проблему из системы шаблонов: напишите отдельный фрагмент кода для запроса записей и распечатайте результаты в более простой форме, но с теми же данными. Если это все еще медленно, добавьте его к вопросу, чтобы мы могли видеть, что вы делаете. Если это быстро, то вы немного сузили проблему. Glenn Maynard
Алекс: Моя точка зрения довольно проста. Он выводит начальный список записей, затем, если отчет изменяется, он добавляет некоторые фильтры. Это действительно так. Затем мой шаблон группирует набор данных в два раздела, а затем проходит по всему циклу, вызывая в процессе теги-шаблоны (но я рассчитал, что теги шаблона должны быть выполнены за 0,1 -> 0,5 секунды ... эти теги-шаблоны являются промежуточными итогами / итогами отчет, так что время выполнения на больших наборах данных в порядке.) Bartek

Ваш Ответ

4   ответа
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

Я надеюсь, что это, по крайней мере, может указать вам в правильном направлении ...

Я также не думаю, что ваше узкое место в производительности находится в шаблонизаторе. Вы можете использовать некоторые таймеры вокруг ключевых вызовов в вашем представлении, чтобы попытаться найти самые медленные части кода Python и улучшить его оттуда.
К сожалению, в некоторых серьезных случаях пользователь хочет получить отчет о годовых данных о продажах, и я не могу сохранить записи на более низком уровне. .. :) Bartek
Проблема, с которой вы можете столкнуться при добавлении чисел, умножении чисел - это количество записей. Если количество возвращаемых записей будет меньше, это уменьшит накладные расходы памяти и количество времени, необходимое для обработки этих данных. Имейте это в виду: вы не можете сделать приложение быстрее, вы можете только заставить его выполнять меньше работы.
Благодарю. Вы правы, это имеет смысл. Я видел запросы, выполняющиеся нормально и с низким MS, поэтому я никогда не рассматривал это. Проблема, конечно, в том, что ORM хорош и сохраняет код намного чище в подобных случаях, поэтому я бы с удовольствием не шел по этому пути, если это вообще возможно. Обработка чисел, которую я делаю, не сложна (добавьте эти три числа, умножьте это), а затем я просто выводю их, используя фильтры | intcomma и | floatformat: 2 django, так что я не уверен, является ли это ядром вопрос. Bartek
Я также провел некоторое базовое тестирование с использованием временного модуля, и в моем представлении или в тегах шаблонов не было ничего, что превышало бы огромное время обработки. Еще одним доказательством того, что рендеринг может быть проблемой, является то, что если я выберу & quot; Totals Only & quot; фильтр для моего отчета, который, как вы уже догадались, покажет только итоги, он будет отображаться гораздо быстрее. Чтобы моя страница достигла первого тега шаблона для промежуточных итогов, требуется около 10 секунд, когда я показываю все данные. Bartek
2

ресурсов процессора и памяти, используяValuesQuerySet это обеспечивает более непосредственный доступ к результатам запроса вместо создания экземпляра объекта модели для каждой строки в результате.

Его использование выглядит примерно так:

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

использование ORM может привести к неоптимальным запросам SQL.

Как отмечали некоторые, невозможно определить, что на самом деле представляет собой зонд, только с помощью предоставленной вами информации.

Я просто могу дать вам общий совет:

If your view is working with related model objects, consider using select_related(). This simple method might speed up the queries generated by the ORM considerably. Use the Debug Footer Middleware to see what SQL queries are generated by your views and what time they took to execute.

PS: Просто к вашему сведению, у меня когда-то был довольно простой взгляд, который был очень медленным. После установкиПромежуточное программное обеспечение отладки нижнего колонтитула Я видел это около 500! SQL запросы были выполнены в этом единственном представлении. Просто используяselect_related () довел это до 5 запросов, и представление было выполнено, как и ожидалось.

2

& quot; tokenize. что может иметь некоторый смысл, так как я занимаюсь форматированием чисел. & Quot;

Не имеет никакого смысла вообще.

Увидетьhttp://docs.python.org/library/tokenize.html.

The tokenize module provides a lexical scanner for Python source code, implemented in Python

Выход Tokenize на вершину означает, что у вас есть динамический анализ кода.

AFAIK (выполняет поиск в репозитории Django) Django не использует токенизацию. Таким образом, ваша программа выполняет какую-то динамическую реализацию кода. Или вы только профилируетеfirst время, когда ваша программа загружена, проанализирована и запущена, что приводит к ложным предположениям о том, куда идет время.

Вам следуетnot когда-либо делайте вычисления в шаблонных тегах - это медленно. Он включает в себя сложную мета-оценку тега шаблона. Вы должны делать все вычисления в представлении в простом Python с минимальными издержками. Используйте шаблоны только для презентации.

Кроме того, если вы постоянно выполняете запросы, фильтры, суммы и что-то еще, у вас есть хранилище данных. Получить книгу о дизайне хранилища данных и следовать шаблонам проектирования хранилища данных.

У вас должна быть центральная таблица фактов, окруженная таблицами измерений. Это очень, очень эффективно.

Суммы, групповые и т. Д., Могут быть сделаны какdefaultdict операции в Python. Массовое извлечение всех строк, построение словаря с желаемыми результатами. Если это слишком медленно, то вы должны использовать методы хранения данных для сохранения постоянных сумм и групп отдельно от ваших детальных фактов. Часто это включает выход за пределы Django ORM и использование функций RDBMS, таких как представления или таблицы производных данных.

Можете ли вы сказать мне, почему я не должен делать какие-либо вычисления (основное добавление к суммированию чисел) в тегах-шаблонах? После вашего поста я нашел более эффективный способ сделать то, что делают мои шаблоны, который полезен, но все еще не является узким местом. По крайней мере, он сбрит несколько секунд времени на обработку :) Спасибо Bartek

Похожие вопросы