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

Laravel: міграції й сідери

20 питань · ~20 хв · Версія v3.0

Увійдіть, щоб продовжити

Відкат і пакети міграцій, деплой на кілька серверів, стискання схеми, зміни великих таблиць без блокування, зовнішні ключі, сідери - питання всіх рівнів, від junior до lead.

За спробу
20
У пулі
44
Проходжень
0
Середній бал
-
Пройшли на 70%+
-

Питання для підготовки

17 питань

Міграція - це контроль версій для структури бази даних. Замість того щоб писати SQL вручну й узгоджувати його між розробниками, ви описуєте схему PHP-кодом, який комітиться в git і застосовується однаково в усіх середовищах.

Міграції зберігаються в директорії database/migrations. Кожен файл - це клас із двома методами:

  • up() - описує зміни, які треба застосувати (створити таблицю, додати колонку, індекс).
  • down() - описує зворотну операцію для відкату (видалити таблицю чи колонку).

Створити міграцію:

php artisan make:migration create_posts_table

Згенерований файл заповнюють у методі up():

public function up(): void
{
    Schema::create('posts', function (Blueprint $table) {
        $table->id();
        $table->string('title');
        $table->text('body');
        $table->timestamps();
    });
}

public function down(): void
{
    Schema::dropIfExists('posts');
}

Основні команди:

  • php artisan migrate - застосувати нові міграції.
  • php artisan migrate:rollback - відкотити останній «батч».
  • php artisan migrate:fresh --seed - перестворити всі таблиці й засіяти даними.

Навіщо: будь-який розробник на новій машині отримує ідентичну схему БД однією командою, а зміни структури проходять через code review разом із кодом.

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

Деплой без простою: користувачі весь час бачать робочу версію.

Atomic (symlink) deploy - кожен реліз клонується в нову папку, там встановлюються залежності й збираються ассети, після чого current атомарно перемикається через symlink:

releases/2026_06_05_120000/ ← новий
current → releases/... ← атомарне перемикання

Кроки на деплої: composer install --no-dev, npm run build, migrate --force, кеш конфіг/маршрутів, перезапуск воркерів (queue:restart) і OPcache.

Інструменти: Envoyer, Deployer, CI/CD-пайплайни, Kubernetes (rolling update). Окрема увага - сумісність міграцій із попередньою версією коду під час перемикання.

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

Seeding - це процес наповнення бази даних початковими або тестовими даними. Laravel робить це через класи-сідери, які лежать у директорії database/seeders. Зручно для довідників (країни, ролі), демо-контенту та локальної розробки чи тестів.

Створити сідер:

php artisan make:seeder PostSeeder

Логіку вставки описують у методі run() - або через фабрики, або напряму через Query Builder:

class PostSeeder extends Seeder
{
    public function run(): void
    {
        Post::factory()->count(50)->create(); // через фабрику

        // або напряму
        DB::table('roles')->insert([
            ['name' => 'admin'],
            ['name' => 'user'],
        ]);
    }
}

Реєстрація: сідери викликають у DatabaseSeeder::run(), щоб запускати їх разом:

public function run(): void
{
    $this->call([RoleSeeder::class, PostSeeder::class]);
}

Запуск:

  • php artisan db:seed - виконує DatabaseSeeder.
  • php artisan db:seed --class=PostSeeder - конкретний сідер.
  • php artisan migrate:fresh --seed - перестворити БД і засіяти.

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

Головний ризик - несумісність схеми зі старим кодом під час деплою та блокування таблиць.

Безпечні зміни (expand → migrate → contract):

  1. Додати нову колонку (nullable) - старий код працює.
  2. Задеплоїти код, що пише і в стару, і в нову.
  3. Перенести дані (фоновий job), перемкнути читання.
  4. Окремим релізом видалити стару колонку.

Практики:

  • Не покладатися на migrate:rollback у проді - down() може втрачати дані. Краще forward-fix.
  • Великі ALTER на величезних таблицях блокують → онлайн-міграції (pt-online-schema-change, gh-ost).
  • php artisan migrate --force у пайплайні; --isolated, щоб не виконати паралельно на кількох воркерах.
  • Бекап перед руйнівними операціями; прогін міграцій на staging.

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

На таблиці в кілька мільйонів рядків необережна міграція блокує запис на хвилини, і застосунок лежить.

Що блокує довго:

  • Додавання колонки NOT NULL зі значенням за замовчуванням у старих версіях MySQL переписує таблицю цілком. У MySQL 8 і PostgreSQL 11+ це вже метадані, але перевіряти варто саме свою версію.
  • Створення індексу звичайним CREATE INDEX тримає таблицю на час побудови.
  • Зміна типу колонки майже завжди означає перезапис.

Безпечний порядок для нової колонки:

// 1. Спершу nullable - миттєво, без перезапису.
Schema::table('vacancies', function (Blueprint $table) {
    $table->string('short_name')->nullable()->after('title');
});

Далі заповнити дані пачками - окремою командою, не в міграції:

Vacancy::whereNull('short_name')->chunkById(500, function ($vacancies) {
    foreach ($vacancies as $vacancy) {
        $vacancy->update(['short_name' => Str::limit($vacancy->title, 40, '')]);
    }
});

І лише потім, якщо потрібно, робити колонку обовʼязковою - окремою міграцією, коли даних без значення вже немає.

Індекс без блокування:

// PostgreSQL
DB::statement('CREATE INDEX CONCURRENTLY vacancies_level_index ON vacancies (level)');

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

public $withinTransaction = false;

Загальне правило: розділяйте зміну схеми й заповнення даних. Міграція має бути швидкою операцією над структурою, а перенесення даних - командою, яку можна запустити, зупинити й продовжити.

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

Прочитати - ще не значить знати

20 питань, по одному на екран, ~20 хв. Після завершення - розбір кожної помилки з посиланням на питання.