Все зрелые кодовые базы содержат антиблокировки: проблемы с кодом, которые вводят дыры безопасности, технологический долг, который повышает стоимость работы с кодовой базой и код, который идет против лучшей практики, которая замедляет его.
Django доктор Выполняет статический анализ, чтобы найти и автоматически исправить такие проблемы. Мы проверили 666 кодовых база Django для неэффективных вызовов Django ORM и были удивлены степенью проблемы: 50% всех кодовых база Django, которые мы проверили, имели следующие антиблокировки :
- 16% используется
queryset.count ()> 0
вместоQueryset.exists ()
- 15% используется
Лен (запрос)
вместоqueryset.count ()
- 10% проверено
Если запрос:
вместоЕсли QuerySet.exists ():
- 10% не использовали иностранные ключи напрямую
Они в лучшем случае замедляют приложение Django, и в худшую сторону может принести производство.
Как бы вы решили эти результаты антиблокировки? Пытаться Наш рефакторист Performance Django .
Учитывая эти проблемы присутствовали более половины репозиториев Django GitHub, проверено, есть хороший шанс, что у вас есть хотя бы одна из этих проблем. Опытный django dev может думать, что они не сделают эти ошибки, но это не является Dev – это остров: со временем Devs Shame Teams, наследует CodeBase Brownfield, которая накапливала Tech Dovs, и будет рассмотреть код, написанный Junior Devs. Поэтому важно:
- избегать ошибки
- знать, как эффективно найти и исправить ошибку
- знать, как общаться с Junior Devs Почему Это проблема.
Используя .count ()> 0 вместо .exists ()
Сравнение queryset.count ()
менее эффективен, чем проверять Queryset.exists ()
Отказ Django Docs говорит нам использовать queryset.count ()
Если вы хотите только подсчет, и использовать Queryset.exists ()
Если вы хотите узнать, существует ли хотя бы один результат.
Причина этого – потому что queryset.count ()
Выполняет операцию SQL, которая сканирует каждый ряд в таблице базы данных для расчета суммы. С другой стороны Queryset.exists ()
Просто читает одну запись в самый оптимизированный способ :
- Удалить упорядочение
- Удалить группировать
- Очистить любой Dev-определенный
select_related
иотчетливый
от запроса
Так вместо
def check_hounds(): queryset = HoundsModel.objects.all() if queryset.count() > 0: return "oh no. Run!"
Django доктор будет автоматически исправить это:
def check_hounds(): queryset = HoundsModel.objects.all() if queryset.exists(): return "oh no. Run!"
Читать далее
Использование Len (Queryset) вместо QuerySet.count ()
Лен (запрос)
Выполняет количество на уровне приложения. Это намного менее эффективно, чем делать queryset.count ()
, который делает расчет на уровне базы данных и просто возвращает счет.
Напроцеты – это лениво оценивается – означает, что записи не читаются из базы данных до тех пор, пока код не взаимодействует с данными. Вот почему мы можем сделать queryset.all ()
Не загружая каждую записи из базы данных.
Пример чего-то, что взаимодействует с данными, делает Лен (запрос)
. Это Будет ли Прочитайте все записи в запросе: эффективно загрузка базы данных через Интернет. Не особенно эффективен.
С другой стороны, делая queryset.count ()
обрабатывает расчет на уровне базы данных, выполнив SQL, как Выберите Count (*) из таблицы
Отказ Это означает использование queryset.count ()
делает код быстрее и улучшает производительность базы данных. Плюс представить отходы в загрузке 5000 записей только для проверки длины и выбросить их в конце!
Так вместо
def check_hounds(): queryset = HoundsModel.objects.all() if len(queryset) > 2: return "oh no. Run!"
Django доктор будет автоматически исправить это:
def check_hounds(): if HoundsModel.objects.count() > 2: return "oh no. Run!"
Сказав это, хотя, если записи будут нуждаться в чтении после проверки длины, то Лен (запрос)
может быть действительным.
Читать далее
Использование в случае запроса: вместо того, чтобы если QuerySet.exists ():
Подобно выше, это может загрузить каждую строку в таблице базы данных в память, потому что запрос оценивается. Проверка, если запрос правда/falsey намного менее эффективен, чем проверка Queryset.exists ()
Отказ
Это особенно неэффективно, если таблица очень велика: она может привести к тому, что CPU Spike в базе данных и использует много памяти на веб-сервере. Таким образом, вместо того, чтобы вытащить каждый белый ряд со стола, проверьте Queryset.exists ()
, который просто пытается прочитать одну запись из таблицы очень эффективным способом.
Так вместо
def check_hounds(): queryset = HoundsModel.objects.all() if queryset: return "oh no. Run!"
Django доктор будет автоматически исправить это:
def check_hounds(): queryset = HoundsModel.objects.all() if queryset.exists(): return "oh no. Run!"
Читать далее
Не использовать иностранные ключи напрямую
При работе с иностранными ключами доступа к model_instance.relived_field.id
приведет к базе данных, когда rottle_field.id
оценивается. Это можно устранить делать model_instance.related_field_id
, что является внешним ключевым значением, которое Django уже кэшируется на объекте, чтобы сделать этот сценарий более эффективным.
Так вместо
def check_hounds(pk, farm_ids): hound = HoundsModel.objects.get(pk=pk) if hound.farm.id in farm_ids: ...
Django доктор будет автоматически исправить это:
def check_hounds(pk, farm_ids): hound = HoundsModel.objects.get(pk=pk) if hound.farm_id in farm_ids: ...
Читать далее
У вашего Django Code есть эти антиблокировки?
Со временем легко проскользнуть в вашей кодовой базе. Я могу проверить это для вас в django.doctor или может Просмотрите свой GitHUB PRS :
Или попробуйте Рефакторы Django Challenges Отказ
Оригинал: “https://dev.to/djangodoctor/666-django-projects-checked-for-inefficient-database-queries-over-half-had-these-4-anti-patterns-4383”