Django ORM и базы данных
Чем aggregate() отличается от annotate()?
aggregate() завершает QuerySet и возвращает один словарь со сводными значениями. annotate() добавляет вычисленное поле каждой строке результата; вместе с values() оно задает группировку. JOIN по нескольким связям может размножить строки и исказить суммы, поэтому проверяют SQL и при необходимости используют distinct, подзапрос или отдельные агрегации. Агрегаты по пустому набору часто дают NULL. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.
Ссылки для изучения
Как MVCC выбирает видимую версию строки?
PostgreSQL хранит версии строк. Snapshot определяет, какие транзакции считаются видимыми, а служебные xmin и xmax описывают создание и завершение жизни версии. Обычный SELECT обычно не блокирует запись, но записи могут конфликтовать между собой. Старые версии превращаются в dead tuples; autovacuum освобождает их для повторного использования, а долгие транзакции мешают очистке. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.
Ссылки для изучения
Когда нужен SELECT FOR UPDATE?
SELECT ... FOR UPDATE нужен внутри транзакции для сценария read-check-write: выбранные строки блокируются от конкурирующего изменения до завершения транзакции. Обычное чтение блокировка не заменяет. Транзакцию держат короткой, строки берут в стабильном порядке и задают политику ожидания, например timeout, NOWAIT или SKIP LOCKED в PostgreSQL, чтобы управлять дедлоками и очередями. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.
Ссылки для изучения
Примеры хороших ответов из реальных собеседований
- Мок-собеседование Junior Python Developer · 1:00:35–1:01:40Мок-собеседование · Совместный разбор
В обсуждении select for update приводится как пессимистическая блокировка строк перед конкурентным изменением.
Как обработать ошибку внутри ORM-сессии?
Сессию и транзакцию открывают на четкой границе операции. При ошибке делают rollback до повторного использования сессии, затем освобождают ее через контекстный менеджер или finally. Повторяют только классифицированные временные ошибки, например serialization failure или разрыв, и только если операция идемпотентна. Ошибку ограничения данных не лечат слепым retry; ее переводят в понятную доменную ошибку. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.
Ссылки для изучения
Что гарантируют миграции схемы?
Миграции дают версионированный граф изменений схемы и воспроизводимый порядок их применения. Они не гарантируют безостановочность, обратимость каждого DDL или корректность преобразования данных. Большую data migration отделяют, делают повторяемой и наблюдаемой. Перед rollout проверяют поведение конкретной СУБД и версии, блокировки и совместимость старого и нового приложения во время поэтапного деплоя. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.
Ссылки для изучения
Примеры хороших ответов из реальных собеседований
- Как нужно проходить собеседование по Python, чтобы получить оффер! · 19:00–20:30Мок-собеседование · Ответ кандидата
Кандидат объясняет, что миграция фиксирует отличие схемы от предыдущей версии, например изменённые поля модели.
Как разложить задержку запроса к БД по слоям?
Задержку раскладывают на ожидание соединения в пуле, сеть, ожидание блокировки, выполнение плана в БД и передачу или десериализацию результата. Нужны тайминги на каждой границе, slow query log и состояние активных транзакций. EXPLAIN ANALYZE подтверждает фактические строки и время операторов, но сам выполняет запрос, поэтому с изменяющими запросами и production-нагрузкой его применяют осторожно. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.
Ссылки для изучения
Как найти запросы с наибольшей суммарной нагрузкой?
В PostgreSQL pg_stat_statements сортируют по total_exec_time, числу вызовов, среднему времени и чтениям, чтобы отличить редкий медленный запрос от частого дорогого. pg_stat_activity показывает текущие запросы и waits, а системные представления блокировок находят очередь. Затем выбранный нормализованный запрос проверяют через EXPLAIN (ANALYZE, BUFFERS) на безопасном примере и со свежей статистикой. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.
Ссылки для изучения
Когда Django QuerySet выполняет SQL?
Django QuerySet ленив: фильтры строят запрос, а SQL обычно выполняется при итерации, list(), len(), bool(), срезе с шагом и других операциях, требующих результата. После оценки QuerySet кэширует строки для повторного обхода того же объекта. Новый QuerySet или .all() может выполнить запрос заново. Методы exists, count, update и delete отправляют свои запросы сразу. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.
Ссылки для изучения
Как типизировать модель SQLAlchemy 2.0?
В SQLAlchemy 2.0 поля декларативной модели описывают как Mapped[T] = mapped_column(...), а связи как Mapped[Related] или коллекцию. T | None должно согласовываться с nullable=True; это разные уровни, но расхождение вводит в заблуждение. Тип связи отражает кардинальность, а relationship не является колонкой. Аннотации помогают анализатору и мапперу, но не валидируют вход API. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.
Ссылки для изучения
Как устранить N+1 в Django ORM?
N+1 находят по числу SQL-запросов при сериализации списка. select_related делает JOIN для одиночных ForeignKey и OneToOne; prefetch_related выполняет отдельный запрос и связывает в Python коллекции и many-to-many. Выбор зависит от кардинальности и объема. Предзагрузка всего графа тоже может быть дорогой, поэтому фиксируют нужные связи и проверяют число запросов тестом или профилировщиком. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.
Ссылки для изучения
Примеры хороших ответов из реальных собеседований
- Как проходит собеседование на Middle Python разработчика: Вопросы и разбор кейса · 16:26–17:54Мок-собеседование · Ответ кандидата
Как вывод связанного поля в списке Django admin приводит к запросу для каждой строки и почему предварительная загрузка связей устраняет N+1.
Когда OFFSET pagination перестает работать эффективно?
Глубокий OFFSET заставляет СУБД найти и отбросить все предыдущие строки, поэтому время растет. При параллельных вставках и удалениях страницы также получают дубли или пропуски. Для длинной ленты используют keyset pagination: стабильный уникальный ORDER BY и условие после последнего ключа, например по (created_at, id). OFFSET остается удобным для небольших административных выборок и перехода к номеру страницы. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.
Ссылки для изучения
Примеры хороших ответов из реальных собеседований
- Java мок-интервью: сервис заказов, Kafka и PostgreSQL · 55:57–57:15Мок-собеседование · Ответ кандидата
Кандидат объясняет cursor-пагинацию через индексный поиск и отмечает, что OFFSET нужен для произвольного перехода на страницу.
Как порядок столбцов влияет на составной индекс?
Составной B-tree индекс полезен запросам, использующим его левый префикс; точные правила зависят от СУБД и условий. Порядок выбирают по реальным WHERE, диапазонам и ORDER BY, а не по одной лишь селективности столбца. Каждый индекс занимает место и удорожает запись. Решение подтверждают планом и статистикой на похожих данных, потому что оптимизатор может предпочесть full scan. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.
Ссылки для изучения
Как безопасно выполнить raw SQL в Django?
В Django значения передают отдельными параметрами через raw() или connection.cursor(), не склеивают строку и не подставляют кавычки вручную. Имена таблиц и столбцов параметрами не становятся, их выбирают из разрешенного набора и корректно quote-ят средствами backend. Запрос помещают в нужную транзакцию, документируют диалект СУБД, проверяют план и покрывают интеграционным тестом. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.
Ссылки для изучения
Почему сервису нужен ограниченный пул соединений?
Каждое соединение расходует память и работу БД, а тысячи конкурентных запросов создают contention вместо роста throughput. Лимит пула рассчитывают из общего бюджета БД на все реплики и фоновые процессы. Когда пул занят, ожидание создает управляемый backpressure; у него должен быть timeout и метрика. Соединение всегда возвращают в пул, завершая или откатывая транзакцию, иначе утечка быстро исчерпает лимит. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.
Ссылки для изучения
Примеры хороших ответов из реальных собеседований
- Мок-интервью на Middle Python Backend · 32:16–32:55Мок-собеседование · Ответ кандидата
Кандидат объясняет, что пул держит ограниченное число долгоживущих соединений, учитывает лимит базы и избегает дорогого пересоздания соединения для каждого запроса.
Когда ALTER TABLE переписывает большую таблицу?
Цена ALTER TABLE зависит от СУБД, версии и конкретной операции. Смена типа, materialized default, проверка существующих строк или некоторые изменения хранения могут переписать таблицу; создание индекса и validation долго читают данные и берут блокировки разной силы. Перед production rollout проверяют документацию своей версии и репетицию на копии, используют совместимые фазы expand-migrate-contract и готовят откат приложения. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.
Ссылки для изучения
Какие риски есть у ON DELETE CASCADE?
ON DELETE CASCADE удобно поддерживает ссылочную целостность, но одно удаление может запустить большую и неожиданную цепочку, долго держать блокировки и раздувать транзакционный лог. Внешние ключи дочерних таблиц обычно индексируют, чтобы поиск зависимостей не сканировал их целиком. Для важных сущностей часто нужна явная бизнес-операция, аудит или soft delete. Массовое удаление репетируют и ограничивают пакетами. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.
Ссылки для изучения
Когда GenericForeignKey хуже обычного ForeignKey?
GenericForeignKey хранит пару content_type и object_id, позволяя ссылаться на модели разных типов. Цена: обычный внешний ключ БД не гарантирует существование цели, каскады и запросы сложнее, select_related не работает как для нормальной связи. Если набор целей известен, отдельные ForeignKey, общая таблица или явная модель связи обычно надежнее. Полиморфизм оправдан только реальным доменным требованием. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.
Ссылки для изучения
Какую ответственность должен иметь ModelViewSet?
ModelViewSet связывает стандартные CRUD actions с queryset, serializer, permissions и router. Он должен адаптировать HTTP-вход, выбрать данные, вызвать прикладную операцию и сформировать ответ. Длинные транзакции, правила домена и интеграции лучше вынести в сервисы или модели с ясной границей. При этом не нужна абстракция ради абстракции: простая проверка, относящаяся только к endpoint, может остаться во ViewSet. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.
Ссылки для изучения
Когда SerializerMethodField создает N+1?
SerializerMethodField вызывает get_<field> для каждого сериализуемого объекта и является read-only. Если метод каждый раз обращается к непрефетченной связи или выполняет aggregate, список создает N+1. Данные заранее добавляют через select_related, prefetch_related или annotate, а метод читает подготовленное значение. Число запросов проверяют на списочном endpoint, потому что один объект проблемы не показывает. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.
Ссылки для изучения







