Как фильтровать данные в 100 раз быстрее в Django с помощью Redis

В последнее время я оптимизировал производительность приложения, построенного на Django и DRF. Производительность была низкой, так как несколько обращений к базе данных выполнялись для одной и той же таблицы, содержащей почти статические данные (данные менялись примерно раз в неделю). Хорошим решением было бы кэшировать весь набор запросов для модели, однако это было не очень удобно, так как для каждого вызова БД к модели применялся другой набор фильтров.

Факторы, способствующие плохой работе

  1. Множественные вызовы базы данных увеличивают задержку в сети, а также создают нагрузку на серверы баз данных.

  2. Отсутствие возможности выполнять фильтры в наборе запросов, если весь набор запросов должен быть кэширован с помощью Redis.

Модель Mixin спешит на помощь

Мы создадим миксин для наших моделей Django, который добавит возможности кэширования наборов запросов и применит относительно простые фильтры в памяти к этим наборам запросов.

Примечание. Это хороший вариант, только если в таблице несколько тысяч строк и данные относительно постоянны в течение определенного периода времени. Для больших таблиц (более 10 000 строк) всегда лучше позволить мощным серверам баз данных и механизмам обработки выполнять фильтрацию.

Давайте начнем с предположения, что простое приложение Django (имя ‘school_management’) настроено вместе с redis (Как настроить Редис).

Создайте файлы в каталоге приложения с именем model_mixins.py со следующим содержание.

Давайте создадим быстрые модели для использования этого миксина. Вы можете найти код модели здесь

post_save.connect(clear_student_cache, sender=Student)
post_delete.connect(clear_student_cache, sender=Student)

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

Вот краткий справочник по запросу кэшированного набора данных с помощью миксина вместе с соответствующим запросом Django.

# Get all objects
q_db = Student.objects.all()
q_cache = Student.get_all_from_cache()

# Simple attribute Filter
q_db = Student.objects.filter(name="John")
q_cache = Student.filter_from_cache(name="John")

# Filter using list
q_db = Student.objects.filter(age__in=[15,20,25])
q_cache = Student.filter_from_cache(age=[15,20,25])

# Filter using foreign key reference
q_db = Student.objects.filter(school__name="MIT")
q_cache = Student.filter_related_from_cache(school={"name": "MIT"})

# Chaining Filters
q_db = Student.objects.filter(
    age__in=[10,20], school__name="MIT"
)
q_cache = Student.filter_from_cache(age=[10,20])
q_cache = Student.filter_related_from_cache(
    q, school={"name": "MIT"}
)

Вывод

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

Я хотел бы услышать ваши отзывы об этом подходе, помог ли он вам повысить производительность, можно ли улучшить этот метод и т. д.

Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *