Выбор ответа Senior SQLAlchemy 2.0 обновлено

Как не пропустить N+1 в SQLAlchemy

Вопрос

Как сделать так, чтобы случайная ленивая загрузка связи в новом коде сразу ломала тесты, а не тихо делала N+1 в проде?

Попробуйте сами

Выберите вариант, и откроется разбор.

Показать ответ и разбор

Коротко

Правильный ответ: Добавить raiseload("") или lazy="raise", чтобы ленивая загрузка падала. С raiseload любая попытка неявно подгрузить связь заканчивается ошибкой, и разработчик вынужден явно указать selectinload или joinedload.

Варианты ответа

  1. Включить echo=True в проде и настроить алерт на рост числа SQL-запросов
  2. Добавить raiseload("*") или lazy="raise", чтобы ленивая загрузка падалаправильный ответ
  3. Увеличить пул соединений, чтобы N+1 не упирался в лимит и не падал
  4. Использовать expire_on_commit=True, чтобы связи перечитывались явно

Разбор

С raiseload любая попытка неявно подгрузить связь заканчивается ошибкой, и разработчик вынужден явно указать selectinload или joinedload. В async это вдобавок превращает невнятный MissingGreenlet в понятное сообщение. echo полезен для отладки, но не ловит регрессии автоматически, а пул и истечение атрибутов к N+1 отношения не имеют.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.

Термины по теме