Вопросы по работе с базой данных в Python на собеседовании
Работа с базой данных отделяет тех, кто писал сервисы, от тех, кто писал скрипты. Спрашивают про сессию и транзакцию, про N+1 в ORM и про то, что произойдёт с соединением, если запрос завис.
Из чего состоит тема
Так тема разложена в тренажёре: движок ведёт прогресс по каждой подтеме отдельно и возвращает те, где вы ошибаетесь.
- Async SQLAlchemy12
- SQLAlchemy ORM12
- Сессия и Unit of Work12
- Транзакции и изоляция12
- Django ORM11
- Миграции (Alembic)11
- Проблема N+111
- Пулы соединений и Redis11
Разборы подтем
Конспект по каждой: что это, как отвечать вслух, на чём валятся, плюс вопросы для самопроверки.
- Async SQLAlchemy12 вопросов
- Пулы соединений и Redis11 вопросов
- Миграции с Alembic11 вопросов
- Проблема N+1 в ORM11 вопросов
- Django ORM11 вопросов
- SQLAlchemy ORM12 вопросов
- Сессия и Unit of Work12 вопросов
- Транзакции и уровни изоляции12 вопросов
Примеры вопросов с разбором
- Что нужно, чтобы работать с SQLAlchemy асинхронно (create_async_engine)?A)Отдельный сервер очередей, через который SQLAlchemy будет делать запросы в фонеB)Асинхронный драйвер БД, например asyncpg, а не синхронный psycopg2C)Ничего особенного: драйвер работает и в синхронном, и в асинхронном режиме одинаковоD)Достаточно обернуть обычный синхронный движок в async и добавить await к запросам
показать ответ и разбор
+B)Асинхронный драйвер БД, например asyncpg, а не синхронный psycopg2// разбор: Асинхронный SQLAlchemy строят на create_async_engine с async-драйвером: для Postgres это asyncpg (URL postgresql+asyncpg://) или psycopg3 в async-режиме. Синхронный psycopg2 в async-движок не годится — он блокирует. Async-стек даёт AsyncSession с await у операций, но требует всей цепочки async: драйвер, движок, сессия.
- Зачем приложению пул соединений с базой?A)Кэшировать результаты запросов, чтобы не ходить в базу повторноB)Шифровать трафик между приложением и базой данных по умолчаниюC)Автоматически шардировать данные между несколькими базамиD)Переиспользовать соединения, не открывая их на каждый запрос
показать ответ и разбор
+D)Переиспользовать соединения, не открывая их на каждый запрос// разбор: Открытие соединения с БД дорого (TCP, аутентификация, инициализация). Пул держит набор готовых соединений и выдаёт их запросам, возвращая обратно после использования, — резко снижает задержку и нагрузку. Размер пула ограничивают, чтобы не исчерпать лимит соединений СУБД.
- Зачем нужен Alembic (или миграции Django)?A)Версионируемо и воспроизводимо менять схему БДB)Балансировать нагрузку между репликами базы данных при чтенииC)Автоматически бэкапить базу перед каждым деплоем приложенияD)Кэшировать структуру таблиц, чтобы ускорить запросы приложения
показать ответ и разбор
+A)Версионируемо и воспроизводимо менять схему БД// разбор: Alembic ведёт версионируемую историю изменений схемы: каждая ревизия — шаг вперёд (upgrade) и назад (downgrade), применяемый воспроизводимо на любом окружении. Это заменяет ручные ALTER-ы «на проде по памяти» и синхронизирует схему между разработчиками и стендами.
- Что такое проблема N+1 в ORM?A)1 запрос списка плюс по запросу на связь каждой строкиB)Ошибка, когда транзакция висит на единицу дольше положенногоC)Запрос, который случайно возвращает на одну строку больше нужногоD)Ситуация, когда в таблице ровно на одну запись больше индекса
показать ответ и разбор
+A)1 запрос списка плюс по запросу на связь каждой строки// разбор: N+1: сначала один запрос достаёт N строк (например авторов), а затем на каждую при обращении к её связи (книги) уходит ещё по запросу — итого N+1. Классический источник тормозов на списках. Лечится жадной загрузкой связи заранее (eager loading).
- Зачем в Django ORM выражения
F()(напримерF('count') + 1)?A)Пометить поле как обязательное к заполнению на уровне формыB)Отфильтровать записи строго по фиксированному числовому значениюC)Форматировать вывод поля при сериализации ответа клиентуD)Обновить поле на стороне БД без гонки read-modify-writeпоказать ответ и разбор
+D)Обновить поле на стороне БД без гонки read-modify-write// разбор: F() ссылается на значение поля на стороне БД: F('count')+1 сгенерирует UPDATE ... SET count = count + 1 одним запросом, без чтения в Python и обратной записи. Это убирает гонку read-modify-write при конкурентных обновлениях счётчиков.
- Чем SQLAlchemy Core отличается от ORM-слоя?A)Core работает только со SQLite, ORM — с остальными базамиB)Core — SQL-выражения и таблицы, ORM — классы на таблицыC)ORM выполняется быстрее, потому что не генерирует SQLD)Это одно и то же, просто два названия одного механизма
показать ответ и разбор
+B)Core — SQL-выражения и таблицы, ORM — классы на таблицы// разбор: SQLAlchemy двухслоен: Core — язык SQL-выражений поверх таблиц и соединений (близко к SQL, без классов-сущностей), ORM — маппинг классов Python на таблицы с сессией и навигацией по связям. ORM построен поверх Core; на сложных запросах часто спускаются к Core.
- Что за паттерн Unit of Work у сессии SQLAlchemy?A)Копит изменения объектов и пишет их пачкой на commitB)Автоматически распараллеливает запросы по нескольким соединениямC)Пишет каждое изменение в базу немедленно, строка за строкойD)Кэширует результаты запросов между разными сессиями приложения
показать ответ и разбор
+A)Копит изменения объектов и пишет их пачкой на commit// разбор: Session реализует Unit of Work: отслеживает новые, изменённые и удалённые объекты и синхронизирует их с БД одной согласованной пачкой на flush/commit, сама расставляя порядок INSERT/UPDATE/DELETE по зависимостям. Ты меняешь объекты — сессия решает, как это записать.
- Что означают буквы ACID у транзакции?A)Availability, Consistency, Isolation, Distribution по CAPB)Access, Cache, Index, Durability — свойства доступа к даннымC)Atomicity, Consistency, Isolation, DurabilityD)Atomicity, Concurrency, Integrity, Distribution системы
показать ответ и разбор
+C)Atomicity, Consistency, Isolation, Durability// разбор: ACID — Atomicity (всё или ничего), Consistency (переход между валидными состояниями), Isolation (параллельные транзакции не мешают друг другу), Durability (зафиксированное переживёт сбой). Это гарантии классических реляционных СУБД для надёжной записи.
- Чем отличается выполнение запроса в AsyncSession от обычной сессии?A)Запросы автоматически распараллеливаются по ядрам процессора внутри одной сессииB)Операции ожидают через await: await session.execute(...), await session.commit()C)Ничем: методы вызываются точно так же, без await, а асинхронность включается самаD)AsyncSession возвращает результаты синхронно, но открывает соединение в отдельном потоке
показать ответ и разбор
+B)Операции ожидают через await: await session.execute(...), await session.commit()// разбор: AsyncSession повторяет API обычной сессии, но операции ввода-вывода — корутины: их ожидают через await (await session.execute(stmt), await session.commit(), await session.get(...)). Забытый await оставит корутину невыполненной. Смысл — не блокировать цикл событий на время запроса к БД, обслуживая тем временем другие запросы приложения.
это 9 из 92
Ещё 83 вопросов по теме — в тренажёре, с движком повторения
Прочитать разбор и ответить самому — разные навыки. В Сеньорчике вопросы идут сессиями, а движок возвращает подтемы, где вы ошибаетесь, пока они не начнут отскакивать. Бесплатно, лимит по энергии.
Частые вопросы
Спрашивают ли SQLAlchemy наизусть?
Синтаксис почти никогда. Спрашивают модель работы: что такое сессия, когда происходит flush и commit, чем ленивая загрузка опасна и как её контролировать.
Что такое проблема N+1 и как её ловят?
Это когда на каждую запись из основного запроса ORM делает ещё один запрос за связанными данными. Лечится жадной загрузкой или join, а ловится логированием SQL и профилированием.