Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти
Інше
Події Про нас

Middle: питання на співбесіді з теми «Database»

Найпопулярніші питання з реальних Laravel/PHP співбесід для всіх рівнів

4 питання

Транзакція гарантує атомарність: або всі операції виконуються, або жодна.

DB::transaction(function () use ($order) {
    $order->save();
    $order->items()->createMany($items);
    Inventory::decrement($order->product_id, $order->qty);
});

При винятку всередині замикання Laravel автоматично робить rollBack(). Ручний контроль:

DB::beginTransaction();
try {
    // ...
    DB::commit();
} catch (Throwable $e) {
    DB::rollBack();
    throw $e;
}

Другий аргумент transaction($cb, 3) задає кількість повторів при deadlock.

Докладніше в документації: Транзакції БД

Індекс - структура (зазвичай B-дерево), що пришвидшує пошук і сортування за стовпцем ціною уповільнення запису та додаткового місця.

$table->index('status'); // звичайний
$table->unique('email'); // унікальний
$table->index(['user_id', 'created_at']); // композитний

Правила:

  • Індексуйте стовпці у WHERE, JOIN, ORDER BY, зовнішні ключі.
  • Композитний індекс корисний за префіксом стовпців (порядок важливий).
  • EXPLAIN показує, чи використовується індекс.
  • Зайві індекси шкодять записам - балансуйте.

Докладніше в документації: Індекси в міграціях

Підзапит - запит, вкладений в інший. Eloquent дозволяє вставляти їх у select, where, orderBy.

// додати останню дату входу кожного користувача одним запитом
User::addSelect(['last_login_at' => Login::select('created_at')
    ->whereColumn('user_id', 'users.id')
    ->latest()
    ->limit(1),
])->get();

// сортування за підзапитом
Destination::orderByDesc(
    Flight::select('arrived_at')->whereColumn('destination_id', 'destinations.id')->latest()->limit(1)
)->get();

Підзапити допомагають уникнути N+1 і зайвих операцій JOIN, обчислюючи похідні значення в межах одного запиту.

Докладніше в документації: Subqueries

Підключення оголошуються в config/database.php. Вибір конкретного:

DB::connection('reporting')->table('events')->get();

class AnalyticsEvent extends Model
{
    protected $connection = 'reporting'; // модель завжди на цьому з'єднанні
}

Типові сценарії:

  • Read/Write splitting - окремі хости для читання й запису (Laravel сам маршрутизує SELECT на репліку):
    'mysql' => ['read' => [...], 'write' => [...]],
    
  • Окрема аналітична або legacy-БД.

Докладніше в документації: Кілька підключень до БД