Как писать запросы к базе данных
Что проверяют
Умеете ли вы работать и через SQL, и через ORM, и знаете ли базовые правила безопасности и производительности.
Как отвечать
Разложите по слоям.
Безопасность: значения передаются параметрами, никогда не склеиваются со строкой запроса. Это защищает от инъекций и заодно позволяет базе переиспользовать план.
cur.execute("select id, email from users where created_at > %s", (since,))Соединения: используется пул, а не новое подключение на каждый запрос. Соединение и курсор закрываются менеджером контекста, чтобы не текли.
Транзакции: явные границы, короткие транзакции, откат при ошибке. Долгая транзакция держит блокировки и мешает всем.
ORM против сырого SQL: типовые операции с сущностями удобнее через ORM (SQLAlchemy, Django), отчёты и массовые операции пишутся SQL. Важно понимать, какой запрос сгенерировала ORM, и уметь его посмотреть.
Производительность: проблема N+1 лечится предзагрузкой связей (selectinload, select_related), пагинация делается по ключу, а не большим сдвигом, выбираются только нужные колонки, массовые вставки идут пакетами, а не по строке.
Проверка: план запроса через EXPLAIN (ANALYZE, BUFFERS), индексы под конкретные запросы, актуальная статистика.
Полезно добавить про миграции: схема меняется через инструмент вроде Alembic, а не руками, и изменения делаются обратно совместимо, чтобы старая версия приложения продолжала работать во время выката.
Где спотыкаются
Собирают запрос конкатенацией строк и открывают инъекцию.
Пишут через ORM, не глядя на сгенерированный SQL, и получают сотни запросов вместо одного.
Оставляют открытую транзакцию на время внешнего вызова и блокируют строки на секунды.