1. Что такое уровни изоляции транзакций? Какие есть в PostgreSQL/MySQL? Чем отличается READ COMMITTED от REPEATABLE READ?
💡 Зачем спрашивают: чтобы понять, сталкивались ли вы с фантомными чтениями, грязными данными, неповторяющимися чтениями.
Ответ:
- READ UNCOMMITTED — читает незафиксированные изменения (грязное чтение). В PostgreSQL не поддерживается.
- READ COMMITTED (по умолчанию в PostgreSQL) — видны только зафиксированные данные. Но при повторном SELECT в рамках одной транзакции могут прийти новые строки (фантомные чтения).
- REPEATABLE READ — гарантирует, что повторные SELECT вернут те же данные. В PostgreSQL реализован через MVCC, но не защищает от сериализуемых аномалий.
- SERIALIZABLE — полная изоляция, но может вызывать конфликты сериализации.
Java-пример (Spring Boot + @Transactional):
@Transactional(isolation = Isolation.REPEATABLE_READ)
public List<Order> getOrders(Long userId) {
return orderRepository.findByUserId(userId);
}
Важно: не все СУБД поддерживают все уровни одинаково! В MySQL InnoDB REPEATABLE READ ближе к SERIALIZABLE.
2. Что такое индекс? Как он устроен? Когда он помогает, а когда вредит?
💡 Зачем спрашивают: проверяют, понимаете ли вы стоимость операций DML.
Ответ:
- Индекс — структура данных (чаще всего B-Tree), которая ускоряет поиск по столбцу.
- Помогает при WHERE, JOIN, ORDER BY.
- Вредит при частых INSERT/UPDATE/DELETE — индекс нужно перестраивать.
- Composite index (мультиколоночный) работает слева направо: (a, b, c) — эффективен для WHERE a = ? AND b = ?, но не для WHERE b = ?.
Совет: всегда смотрите EXPLAIN ANALYZE в PostgreSQL!
3. Что такое N+1 проблема? Как её решить в JPA/Hibernate?
💡 Зачем спрашивают: проверяют, умеете ли вы писать эффективный код с ORM.
Ответ:
- Проблема: 1 запрос на родителя + N запросов на детей.
- Решения:JOIN FETCH в JPQL:
@Query("SELECT u FROM User u JOIN FETCH u.orders WHERE u.id = :id")
User findUserWithOrders(@Param("id") Long id);
- @EntityGraph
@EntityGraph(attributePaths = "orders")
Optional<User> findById(Long id);
✅ Best practice: избегайте ленивой загрузки в web-слое — она почти всегда приводит к N+1.
4. Что такое deadlock? Как его избежать? Как обнаружить в PostgreSQL?
💡 Зачем спрашивают: проверяют опыт работы с конкурентностью.
Ответ:
- Deadlock — циклическое ожидание ресурсов между двумя+ транзакциями.
- Избежать:Блокировать ресурсы в одном порядке,
Делать транзакции короткими,
Использовать SELECT FOR UPDATE SKIP LOCKED (для очередей). - В PostgreSQL: смотреть логи (log_lock_waits = on) или использовать pg_stat_activity.
Java: ловите PersistenceException → проверяйте причину → retry-логика.
5. Чем VARCHAR(255) отличается от TEXT в PostgreSQL? Есть ли смысл ограничивать длину?
💡 Зачем спрашивают: проверяют знание внутреннего устройства СУБД.
Ответ (PostgreSQL-specific):
- В PostgreSQL нет разницы в производительности между VARCHAR(n), VARCHAR, TEXT.
- Все хранятся как varlena (переменная длина).
- Ограничение длины (VARCHAR(50)) — это ограничение бизнес-логики, а не оптимизация.
- Но: в других СУБД (MySQL, Oracle) разница есть!
✅ Рекомендация: используйте TEXT + валидацию на уровне приложения (например, @Size(max = 255) в Bean Validation).
6. Как работает EXPLAIN? Что означают Seq Scan, Index Scan, Bitmap Heap Scan?
💡 Зачем спрашивают: проверяют, умеете ли вы читать план выполнения.
Ответ:
- Seq Scan — полное сканирование таблицы (плохо при больших данных).
- Index Scan — идёт по индексу, затем по таблице.
- Bitmap Heap Scan — используется при множественных условиях: сначала строится bitmap из индексов, потом читаются строки.
Совет: если видите Seq Scan на большой таблице — скорее всего, нужен индекс.
7. Что такое CTE? Когда использовать WITH вместо подзапроса?
💡 Зачем спрашивают: проверяют знание современного SQL.
Ответ:
- CTE (WITH) — временный именованный результат, улучшает читаемость.
- В PostgreSQL рекурсивные CTE позволяют работать с иерархиями (например, деревья категорий).
- Начиная с PostgreSQL 12, CTE не материализуются по умолчанию — оптимизатор может встроить их.
Пример (рекурсивный CTE для дерева):
WITH RECURSIVE tree AS (
SELECT id, parent_id, name FROM categories WHERE id = 1
UNION ALL
SELECT c.id, c.parent_id, c.name FROM categories c
JOIN tree t ON c.parent_id = t.id
)
SELECT * FROM tree;
8. Что такое connection pool? Почему нельзя создавать Connection вручную в Spring Boot?
💡 Зачем спрашивают: проверяют понимание производительности и ресурсов.
Ответ:
- Создание соединения — дорогая операция (TCP handshake, аутентификация).
- Connection pool (HikariCP в Spring Boot) переиспользует соединения.
- Если создавать Connection вручную — вы быстро исчерпаете лимиты СУБД.
Java 11 + Spring Boot: Hikari настроен по умолчанию. Не трогайте DriverManager.getConnection()!
9. Что такое миграции БД? Почему нельзя менять схему вручную?
💡 Зачем спрашивают: проверяют зрелость в DevOps-практиках.
Ответ:
- Миграции (Flyway, Liquibase) — версионирование схемы БД.
- Позволяют:Воспроизводить окружение,
Откатываться,
Избегать “works on my machine”. - Никогда не меняйте схему вручную в продакшене!
10. Как выбрать между UUID и BIGINT в качестве первичного ключа?
💡 Зачем спрашивают: проверяют системное мышление.
Ответ:
Критерий
BIGINT (SEQUENCE)
UUID
Производительность
Выше (int сравнение)
Ниже (16 байт, фрагментация)
Распределённость
Требует центрального генератора
Можно генерить на клиенте
Безопасность
Угадываемый ID
Непредсказуемый
Размер
8 байт
16 байт
11. Что такое partial index? Приведите пример использования.
💡 Зачем спрашивают: проверяют знание продвинутых возможностей СУБД.
Ответ:
- Partial index — индекс по подмножеству строк.
- Экономит место и ускоряет поиск.
Пример (PostgreSQL):
-- Индекс только для активных пользователей
CREATE INDEX idx_users_active_email ON users(email) WHERE active = true;
✅ Используйте, когда часто фильтруете по одному значению флага.
12. Как работает MVCC в PostgreSQL? Почему SELECT не блокирует UPDATE?
💡 Зачем спрашивают: проверяют понимание архитектуры СУБД.
Ответ:
- MVCC (Multi-Version Concurrency Control) — каждая транзакция видит снимок данных на момент старта.
- UPDATE создаёт новую версию строки, старая остаётся для других транзакций.
- Поэтому SELECT и UPDATE не блокируют друг друга (в большинстве случаев).
✅ Это причина, почему PostgreSQL масштабируется лучше, чем MySQL с MyISAM.
13. Что такое PreparedStatement? Почему нельзя использовать конкатенацию строк для SQL?
💡 Зачем спрашивают: проверяют базовую безопасность.
Ответ:
- PreparedStatement — параметризованный запрос.
- Защищает от SQL-инъекций.
- Повышает производительность (план кэшируется).
Java 11 (правильно):
String sql = "SELECT * FROM users WHERE email = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, email);
// ...
}
Никогда так:
// ❌ УЯЗВИМОСТЬ!
String sql = "SELECT * FROM users WHERE email = '" + email + "'";
4. Когда использовать NoSQL (MongoDB), а когда SQL (PostgreSQL)?
💡 Зачем спрашивают: проверяют способность выбирать технологию под задачу.
Ответ:
- SQL: строгая схема, транзакции, отношения, отчёты.
- NoSQL: гибкая схема, горизонтальное масштабирование, документы.
Примеры:
- Онлайн-кинотеатр (билеты, места, транзакции) → PostgreSQL.
- Логи пользовательских событий → MongoDB.
5. Как вы обеспечиваете согласованность данных в распределённой системе?
💡 Зачем спрашивают: проверяют опыт в микросервисной архитектуре.
Ответ:
- Saga pattern — последовательность локальных транзакций с компенсирующими действиями.
- Outbox pattern — запись событий в ту же транзакцию, что и данные.
- Eventual consistency — принятие того, что данные сойдутся со временем.