Коротка відповідь. Питання «SQL чи NoSQL» на співбесіді перевіряє не знання назв, а вміння міркувати від даних: які зв'язки між сутностями, наскільки важлива консистентність, як читається і пишеться інформація. Сильна відповідь завжди починається з «залежить від задачі» і продовжується конкретними критеріями. Слабка – з «NoSQL швидший». Нижче – один приклад у двох моделях і готова рамка аргументації.
Одна задача – дві моделі
Візьмемо магазин: користувачі, товари, замовлення. Замовлення містить кілька товарів із кількістю.
Реляційна модель (PostgreSQL)
Дані нормалізовані: кожна сутність у своїй таблиці, зв'язки через зовнішні ключі:
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email TEXT NOT NULL UNIQUE
);
CREATE TABLE products (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title TEXT NOT NULL,
price_cents INTEGER NOT NULL CHECK (price_cents >= 0)
);
CREATE TABLE orders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE order_items (
order_id UUID NOT NULL REFERENCES orders(id),
product_id UUID NOT NULL REFERENCES products(id),
quantity INTEGER NOT NULL CHECK (quantity > 0),
PRIMARY KEY (order_id, product_id)
);«Усі замовлення користувача з товарами» – це JOIN:
SELECT o.id, o.created_at, p.title, oi.quantity
FROM orders o
JOIN order_items oi ON oi.order_id = o.id
JOIN products p ON p.id = oi.product_id
WHERE o.user_id = $1
ORDER BY o.created_at DESC;Що дає модель: база сама гарантує цілісність (не можна створити замовлення неіснуючого користувача), а нові способи читання даних не вимагають зміни схеми.
Документна модель (MongoDB)
Замовлення – один документ, у який вкладено товари:
// Колекція orders
{
_id: ObjectId('...'),
userId: ObjectId('...'),
createdAt: ISODate('2026-09-24T10:00:00Z'),
items: [
{ productId: ObjectId('...'), title: 'Клавіатура', priceCents: 250000, quantity: 1 },
{ productId: ObjectId('...'), title: 'Кабель USB-C', priceCents: 40000, quantity: 2 },
],
}Читання замовлення – один запит без JOIN, і це головна сила: документ зібраний так, як його споживає застосунок. Ціна: назва товару скопійована в документ. Якщо товар перейменували, старі замовлення зберігають стару назву – для історії замовлень це навіть правильно, але це РІШЕННЯ, яке треба ухвалити свідомо, а не отримати випадково.
Критерії вибору
| Критерій | Схиляє до SQL | Схиляє до NoSQL (документи) |
|---|---|---|
| Зв'язки | Багато зв'язків «багато-до-багатьох», запити з різних боків | Дані читаються цілісними агрегатами |
| Консистентність | Критична (гроші, залишки, бронювання) | Прийнятна eventual consistency |
| Схема | Стабільна, спільна для команд | Часто змінюється, різнорідні об'єкти |
| Запити | Заздалегідь невідомі, аналітика, звіти | Відомі наперед, прості за ключем |
| Транзакції | Між кількома сутностями регулярно | Здебільшого в межах одного документа |
І чесне доповнення для співбесіди: у більшості продуктових задач PostgreSQL – розумний вибір за замовчуванням, бо покриває і JSON-поля, і повнотекстовий пошук, і горизонтальне читання через репліки. NoSQL обирають під конкретний профіль навантаження, а не «на всяк випадок».
ACID простими словами
- Atomicity – транзакція виконується повністю або не виконується взагалі. Списання коштів і створення замовлення не можуть «розійтися».
- Consistency – після транзакції дані відповідають правилам схеми (унікальність, зовнішні ключі, CHECK).
- Isolation – паралельні транзакції не бачать проміжних станів одна одної. Рівні ізоляції – компроміс між строгістю і швидкістю.
- Durability – закомічені дані переживають падіння сервера.
Практичний приклад для відповіді: два покупці одночасно купують останню одиницю товару. Без ізоляції обидва побачать «є 1 шт» і обидва оформлять замовлення. Транзакція з блокуванням рядка або перевіркою залишку в UPDATE вирішує це на рівні бази.
Типові міфи
- «NoSQL швидший». Швидшим є читання одного документа без JOIN. Але запит «усі замовлення з товаром X за місяць» у документній моделі може вимагати сканування всієї колекції. Швидкість залежить від відповідності моделі й запитів, а не від класу бази.
- «SQL не масштабується». Реляційні бази масштабуються реплікацією на читання і шардингом; величезні продукти живуть на PostgreSQL і MySQL. Складнішим є саме шардинг із транзакціями між шардами, і чесно назвати це обмеження – плюс на співбесіді.
- «У NoSQL немає транзакцій». У MongoDB транзакції на кілька документів існують; але модель даних зазвичай будують так, щоб вони були рідкістю. Деталі – в офіційній документації MongoDB.
- «Схема в NoSQL не потрібна». Схема є завжди, питання лише де: у базі чи в коді застосунку. «Schemaless» означає, що помилки схеми виявляться в runtime.
А що з JSON у PostgreSQL?
Окреме питання, яке любить середина співбесіди: «навіщо тоді NoSQL, якщо в PostgreSQL є JSONB?» Чесна відповідь: JSONB закриває значну частину кейсів «гнучкої» частини даних – атрибути товарів різних типів, налаштування користувача, сирі payload-и вебхуків. Можна індексувати поля всередині JSON і поєднувати їх зі звичайними реляційними колонками:
CREATE TABLE products (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title TEXT NOT NULL,
attributes JSONB NOT NULL DEFAULT '{}'
);
-- Індекс під пошук за атрибутом
CREATE INDEX idx_products_brand ON products ((attributes->>'brand'));Це не робить документні бази непотрібними, але ще раз підтверджує правило за замовчуванням: почни з PostgreSQL, ускладнюй інфраструктуру лише під виміряну потребу.
Сильна vs слабка відповідь
Питання: «Яку базу ти б обрав для сервісу замовлень?»
Слабко: «MongoDB, бо він швидкий і в ньому зручний JSON».
Сильно: «Спершу подивився б на дані й операції. Замовлення пов'язані з користувачами й товарами, потрібні транзакції на списання залишків і звіти по продажах – це аргументи за PostgreSQL. Якщо б окремим сервісом був, наприклад, кошик або стрічка переглядів, де дані читаються одним агрегатом і транзакцій між сутностями немає, там документна база або Redis доречніші. За замовчуванням почав би з PostgreSQL і виносив окремі профілі навантаження за потреби».
Різниця не в правильній назві, а в ході міркування: дані → операції → гарантії → вибір.
Типові помилки у відповідях
- Бінарне мислення. «SQL для серйозних систем, NoSQL для стартапів» – ярлики замість аналізу. Реальні системи комбінують: PostgreSQL як джерело правди, Redis для кешу, іноді документна база під окремий профіль.
- Ігнорування запитів. Кандидат моделює дані, не спитавши, ЯК вони читатимуться. А саме запити визначають, чи буде модель зручною: документна база чудова рівно до першого «а тепер звіт у розрізі товарів».
- Денормалізація без плану оновлення. Скопіював назву товару в документ замовлення – добре; не відповів, що станеться при перейменуванні – мінус. Кожна копія даних має власника і правило життя.
- «Транзакції не потрібні, у нас простий продукт». Достатньо одного переказу коштів, бронювання чи ліміту місць, щоб вони стали потрібні. Краще показати, що ти бачиш такі місця заздалегідь.
- Індекси поза увагою. Різниця між «працює» і «працює на реальних даних» – найчастіше саме індекси. Згадка про EXPLAIN і індекс під конкретний запит одразу піднімає рівень відповіді.
Що потренувати перед співбесідою
- Напиши схему з прикладу вище руками і три JOIN-запити до неї (документація PostgreSQL – найкращий довідник).
- Змоделюй ту саму область документами і сформулюй, які запити стали простішими, а які болючішими.
- Підготуй по одному прикладу задачі «точно SQL» і «точно документи» зі своїм поясненням.
База даних – лише один шар backend-співбесіди; повний маршрут підготовки є в статті про Node.js interview, а про кешування поверх бази – у розборі Redis. Якщо готуєшся системно, глянь і план підготовки за 30 днів.