Comments 7
Спасибо большое за материал!
Достать до конца мне ещё предстоит, но базовые оптимизации уже улучшили моё понимание происходящего при запросах в Django.
Еще попробую применить прочитанное на Tortoise ORM (использую из-за асинхронности)
Спасибо за статью. Сомневаюсь что новички много полезного вынесут - они просто ещё не сталкивались с проблемами, которые тут решаются. А вот мидлам будет полезно.
Пара занудных замечаний
select_related всё же не всегда приводит к INNER JOIN, а только в случае, когда поле имеет null=False. При null=True select_related приведёт к left outer join, что логично и правильно.
Я не сразу понял что вы имеете ввиду под "оценкой" QuerySet. Я понимаю, что все переводчики дают именно такой перевод, но всё же мы не оцениваем QuerySet, а скорее выполняем или исполняем или разрешаем. eval ведь тоже не оценка выражения, а его исполнение.
В статье несколько раз повторяется, но думаю не лишним будет ещё раз подчеркнуть. Все описанные "проблемы" это не недоработки django, а "особенности" реляционных баз данных. ORM это лишь удобный инструмент, позволяющий формировать запросы. Какое то время можно пользоваться им не понимая как работают БД. Но тогда вы будете постоянно удивляться почему плодятся дубли или как то неправильно работает сортировка. Поэтому очень рекомендую разобраться с основами реляционных БД и SQL.
# bigint (8 bytes)
positive_big_integer = models.PositiveSmallIntegerField()
наверное, все-таки, PositiveBigInteger
. И такой вопрос: вы несколько раз упомянули про JsonField. Как-то раз встала задача трекать дату и автора изменения в полях модели (т.е. не изменение всей записи, что можно было бы сделать полем с auto_now, а вот прям по полям). Я сначала решил эту задачу через JsonField и мне казалось вполне нормальным решением. Данные в поле обновлялись по ключу в момент сохранения изменений или создания записи, читались чаще, чем изменялись. Но коллеги в какой-то момент рекомендовали изменить подход и родить таблицу через GenericForeighKey, где каждому полю каждой таблицы, которая должна была быть вовлечена в этот функционал, создавалась обновляемая запись. Аргументом выступало требование к нормализации данных. Как бы вы рекомендовали решить эту задачу? Какой подход с какими плюсами и минусами вы видите?
В целом, можно было использовать и JsonField, но тогда вам каждый раз нужно собирать и разбирать весь объект
С GenericForeignKey справедливое решение, но если уж очень много полей и сущностей, которые нуждаются в такой логике, на мой взгляд, издержек при чтении будет больше, смотря, конечно, как часто вам нужно получать именно время и автора обновления.
Я таким образом обычно храню маппинг внешних id (ID в других приложениях) с внутренним, так как они нужны не так уж часто и могут быть для совершенно разных приложений.
В задаче, которая стояла у вас, я бы все-таки использовал дополнительную таблицу, для каждой сущности. Для удобства был бы написан класс поля модели, который создавал бы дополнительную таблицу для модели владельца. В целом было бы что-то типо кастомной истории
Спасибо, что указали на ошибку, поправлю в статье
Оптимизация запросов в Django. Подробное руководство