Накладные расходы на поездку туда и обратно к MySql?
Вопрос
Итак, я уже некоторое время создаю приложения на django, пью классную помощь и все такое:использовать только ORM и никогда не писать собственный SQL.
Главная страница сайта (основной интерфейс, где пользователи проводят 80–90 % своего времени) работала медленно, если у вас было большое количество пользовательского контента (например, фотографий, друзей, других данных и т. д.).
Итак, я запустил sql-логер (он был предварительно установлен в Pinax, я просто включил его в настройках) и представьте себе мое удивление, когда он сообщил об этом. 500 запросов к базе данных!!Используя написанный вручную sql, я вряд ли когда-либо запускал более 50 самых сложных страниц.
Оглядываясь назад, в этом нет ничего удивительного, но кажется, что это не может быть хорошо.
...даже если около дюжины запросов займут 1 мс+
Поэтому мне интересно, сколько накладных расходов требуется при обращении к mysql туда и обратно?django и mysql работают на тот же сервер поэтому не должно быть никаких накладных расходов, связанных с сетью.
Решение
Есть несколько способов уменьшить объем запросов.
Использовать
.filter()
и.all()
получить кучу вещей;выбирайте в функции просмотра (или в шаблоне через{%if%}
).Python может обрабатывать пакет строк быстрее, чем MySQL.«Но я мог бы отправить слишком много в шаблон».Да, но вы будете выполнять меньше SQL-запросов.Измерьте, чтобы увидеть, что лучше.
Это то, что вы делали, когда писали SQL.В этом нет ничего плохого — это не нарушает ORM, но это оптимизирует базовую работу с базой данных и помещает обработку в функцию представления и шаблон.
Избегайте навигации по запросам в шаблоне.Когда вы выполняете {{foo.bar.baz.quux}}, для получения
bar
связан сfoo
, тогдаbaz
связанный сbar
, тогдаquux
связан сbaz
.Возможно, вам удастся сократить объем этих запросов, проявив некоторую осторожность..filter()
и обработка Python для сборки полезного кортежа в функции представления.Опять же, это то, что вы делали, когда вручную создавали SQL.В этом случае вы собираете большие пакеты объектов, управляемых ORM, в функции просмотра и выполняете фильтрацию на Python вместо множества отдельных запросов ORM.
Это не нарушает ORM.Он меняет профиль использования с множества маленьких запросов на несколько более крупных запросов.
Другие советы
Тот факт, что вы используете ORM, не означает, что вам не следует выполнять настройку производительности.
У меня, как и у вас, была домашняя страница одного из моих приложений с низкой производительностью.Я увидел, что делаю сотни запросов, чтобы отобразить эту страницу.Я посмотрел на свой код и понял, что при осторожном использовании select_related()
мои запросы приносили больше необходимых мне данных — я перешел от сотен запросов к десяткам.
Вы также можете запустить профилировщик SQL и посмотреть, нет ли индексов, которые помогли бы вашим наиболее частым запросам - ну, вы знаете, стандартным материалам базы данных.
Я думаю, что кеширование тоже ваш друг.Если большая часть страницы не меняется, нужно ли вам каждый раз запрашивать базу данных?
Если ничего не помогает, помните:ORM великолепен, и да, вам следует попробовать его использовать, потому что это философия Django; но ты не женат на этом.
Если у вас действительно есть вариант использования, когда изучение и настройка навигации ORM не помогли, если вы уверены, что можно было бы сделать это гораздо лучше с помощью стандартного запроса:используйте в этом случае необработанный sql.
Накладные расходы на каждый запрос — это лишь часть картины.Фактическое время прохождения между вашими серверами Django и Mysql, вероятно, очень мало, поскольку большинство ваших запросов возвращаются менее чем за одну миллисекунду.Более серьезная проблема заключается в том, что количество запросов к вашей базе данных может быстро ее переполнить.500 запросов на страницу — это слишком много, даже 50 мне кажутся много.Если десять пользователей просматривают сложные страницы, у вас теперь до 5000 запросов.
Время туда и обратно до сервера базы данных является более важным фактором, когда вызывающий абонент обращается к базе данных из глобальной сети, где время туда и обратно может легко составлять от 20 до 100 мс.
Я бы определенно рассмотрел возможность использования какого-либо кэширования.
При вызовах базы данных всегда есть накладные расходы, в вашем случае накладные расходы не являются что плохо, потому что приложение и база данных находятся на одном компьютере, поэтому задержек в сети нет, но это все равно требует значительных затрат.
Когда вы делаете запрос к базе данных, она должна подготовиться к обслуживанию этого запроса, выполнив ряд действий, в том числе:
- Выделение ресурсов (буферов памяти, временных таблиц и т. д.) для соединения/потока сервера базы данных, который будет обрабатывать запрос.
- Десериализация SQL и параметров (это необходимо даже на одном компьютере, поскольку это межпроцессный запрос, если вы не используете встроенную базу данных)
- Проверка существования запроса в кеше запросов, если не оптимизировать его и не поместить в кеш.
- Также обратите внимание, что если ваши запросы не параметризованы (то есть значения не отделены от SQL), это может привести к промахам в кэше для операторов, которые должны быть одинаковыми, что означает, что каждый запрос приводит к анализу и оптимизации запроса каждый раз.
- Обработайте запрос.
- Подготовьте и отправьте результаты клиенту.
Это всего лишь обзор того, что делает большинство систем управления базами данных для обработки SQL-запроса.Вы несете эти накладные расходы 500 раз, даже если сам запрос выполняется относительно быстро.Итоговое взаимодействие с базой данных, даже с локальной базой данных, не так дешево, как можно было бы ожидать.