Рубрики
Без рубрики

Исправление неэффективного Django Orm в проектах Brownfield

Один из самых быстрых побед для улучшения скорости приложения Django – это исправить «упс не значит» … Помечено Django, Python, WebDev, CodeQuality.

Один из самых быстрых выигрышей для улучшения скорости приложения Django – это исправить «упс, не значит для» неэффективных чтений базы данных, которые проскользнули в кодовую базу незамеченной в течение многих лет. Действительно, как созревает кодовые базы и изменение членов команды, а кода собирает пыль старые неэффективные ORM-запросы. Простые ORM-запросы, такие как:

def check_hounds():
    queryset = HoundsModel.objects.all()
    if len(queryset) > 2:
         return "oh no. Run!" 

Это читает каждую запись из базы данных и проверять на уровне приложений. Намного менее эффективно, чем

def check_hounds():
    if HoundsModel.objects.count() > 2:
         return "oh no. Run!" 

При таких неэффективности в таких неэффективности легко отменить. «Я бы никогда этого не сделаю». Ну, может быть, нет. Но как насчет некоторой разработки в прошлом, который спешил встретить крайний срок, рецензент по коду в 11:00 одинаково выживших на кофе во время хрустящего времени? И вы теперь несете ответственность за этот код!

Чуть менее учебник, но также так же просто как упускать из виду и улучшения:

def write_condolence_letters(visited_coops):
    queryset = ChickenModel.objects.all()
    for chicken in queryset:
        if chicken.coop.pk in visited_coops:
            return f"dear {chicken.coop.owner_name}..."
        else:
            ...

Найдите проблемы? Ну, зацикливаться на все () прочитал все из БД за один раз. Если есть миллиарды цыплят, то ожидают проблемы с производительностью. Для этого мы можем использовать итератор () Для куска записи Reads 2000 (по умолчанию) вытащили из БД за раз. Кроме того, цыпленок.coop.pk делает дополнительную базу данных для каждой курицы, потому что отношения лениво оценивается По умолчанию: Coop читается из БД, когда только это было доступно через курятник . Для этого конкретного поля мы можем использовать полевой кеширование Django: Django создает _id поле для связанного поля. Так что это может быть:

def write_condolence_letters(visited_coops):
    queryset = ChickenModel.objects.all()
    for chicken in queryset.iterator():
        if chicken.coop_pk in visited_coops:
            return f"dear {chicken.coop.owner_name}..."
        else:
            ...

Что делать, если мы работаем с полем на соответствующей модели, кроме PK? Конечно COUP_PK Для нас создается Django, но что, если нам нужно получить доступ к другим полям, таким как цыпленок.coop.owner_name. ? Для этого мы используем select_related или Prefetch_related (в зависимости от того, если это иностранные отношения или отношения OneToone и т. Д.):

def write_condolence_letters(visited_coops):
    queryset = ChickenModel.objects.all()
    for chicken in queryset.select_related('coop'):
        if chicken.coop.pk in visited_coops:
            return f"dear {chicken.coop.owner_name}..."
        else:
            ...

Теперь связанные Coop будет вытащить в то же самое, как курица Отказ Обратите внимание, хотя итератор больше не используется, потому что итератор бесполезен с select_related и Prefetch_related : Итератор аннулировать свои эффекты. Таким образом, они взаимоисключают, так что только с контекстом мы можем действительно сказать конкретно, что требуется стратегия повышения производительности.

У вашей кодовой базы старые неэффективные ORM Lookups?

Проще определить новые неэффективные поиски ORM во время обзора кода, но как насчет тех, кто уже в вашей кодовой базе? Я могу проверить это для вас в django.doctor или может Просмотрите свой GitHUB PRS :

Или попробуйте Рефакторы Django Challenges Отказ

Оригинал: “https://dev.to/djangodoctor/spotting-inefficient-database-reads-in-django-5a9l”