Завантаження публікації
ОГОЛОШЕННЯ

Міграції в Laravel: foreign keys, індекси, nullable та дефолти — як зробити схему правильно

Пояснюємо простими словами, як проєктувати таблиці міграціями: які поля робити nullable, де ставити default, як правильно робити foreign key і які індекси потрібні для фільтрів, списків та швидкої адмінки.


Максим Третяк
Максим Третяк
Газета Дейком | 30.12.2025, 12:00 GMT+3; 05:00 GMT-4

Міграції — це “паспорт” вашої бази даних у коді. Вони не просто створюють таблиці, вони фіксують правила, які тримають дані живими роками: що з чим пов’язано, які поля можуть бути порожні, які значення мають бути за замовчуванням і як швидко має працювати пошук. Якщо міграції зроблені погано, проєкт починає накопичувати сміття в БД, а будь-які списки та фільтри стають повільними.

Перший принцип: міграція описує структуру так, ніби ти пояснюєш її іншому розробнику без слів. Назва таблиці, назви полів, типи, зв’язки і індекси мають прямо відображати сенс. Новачки часто роблять схему “аби працювало”, але через місяць вона стає пасткою: немає цілісності, все nullable, foreign keys відсутні, індексів немає — і будь-яка аналітика перетворюється на біль.

Почнемо з nullable. Nullable означає, що поле може бути NULL, тобто “значення немає”. Це має бути свідоме рішення. Якщо поле обов’язкове для існування запису (наприклад, title у статті або user_id автора), воно не повинно бути nullable. Якщо поле може з’явитися пізніше або інколи не має сенсу (наприклад, published_at для чернетки, deleted_at для soft delete, main_img_author якщо не вказали автора фото), тоді nullable виправдане.

Головна помилка з nullable — робити nullable “про всяк випадок”. Так ти отримуєш купу записів, де ключові поля порожні, і потім ти починаєш писати десятки умов “якщо поле не порожнє”. Це ускладнює код, вбиває якість даних і часто створює баги на рівні логіки. Правильна дисципліна така: nullable — тільки там, де бізнес-сенс дозволяє відсутність значення.

Далі дефолти (default). Default — це значення за замовчуванням, яке база поставить, якщо ти не передав поле. Це важливо для стабільності. Наприклад, для статусу (draft), для boolean-полів (is_active = true/false), для лічильників (views = 0). Дефолт зменшує кількість “порожніх” випадків і робить поведінку передбачуваною навіть якщо в коді щось не передали.

Але дефолти теж треба ставити з розумом. Не треба ставити default там, де значення має визначатися логікою сценарію. Наприклад, published_at не має дефолту “now”, бо публікація — це дія, а не автоматична подія. user_id теж не має дефолту, бо це прив’язка до конкретного користувача. Дефолт — для стабільних “початкових” станів, а не для важливих бізнес-рішень.

Тепер foreign keys. Foreign key — це зовнішній ключ, який зв’язує таблиці і змушує базу даних тримати цілісність. Простий приклад: якщо в таблиці news є user_id, foreign key гарантує, що цей user_id реально існує в таблиці users. Без цього ти можеш випадково записати user_id = 999999, і база це проковтне. Потім ти будеш ловити “null автора” або падіння на зв’язках.

Foreign keys важливі не лише для “красоти”, а для запобігання системним поломкам. Вони роблять дані самозахищеними: ти не зможеш видалити користувача, якщо на нього посилаються записи (або зможеш, але з контрольованою поведінкою). Це підводить нас до правила on delete: що робити з дочірніми записами, якщо видалили батьківський.

Є кілька типових стратегій. cascade означає: видалили батька — видали і дітей. Це доречно, наприклад, для допоміжних таблиць, які не мають сенсу без батьківського запису. restrict або no action означає: не давай видалити батька, якщо є діти. Це доречно для важливих даних, де видалення не має бути випадковим. set null означає: якщо батька видалили, в дочірньому полі став NULL. Це працює лише якщо поле nullable і якщо бізнес-сенс дозволяє “без батька”.

Окрема дисципліна — узгодженість типів. Якщо users.id — big integer, то і news.user_id має бути таким самим типом. У Laravel сучасний стандарт — foreignId() або foreignIdFor() і constrained(), бо це зменшує ризик помилок і робить код міграцій коротшим і яснішим. Новачкам важливо звикнути саме до цього стилю.

Тепер індекси. Індекс — це те, що робить списки і фільтри швидкими. Якщо таблиця маленька, різниця непомітна. Але в медіапроєкті, де ти маєш десятки тисяч новин, індекси визначають, чи буде адмінка “літати”, чи “думати” по 5 секунд на кожен фільтр. Тому індекси не “оптимізація на потім”, а частина дизайну схеми.

Які поля найчастіше потребують індексів. Перше — всі foreign keys, бо по них йдуть JOIN і фільтри (user_id, section_id, resource_id). Друге — поля, по яких часто фільтрують: статуси, дати, slug, унікальні коди. Третє — поля, по яких часто сортують: published_at, created_at, інколи id як сурогатний порядок. Четверте — комбінації полів, якщо фільтр завжди йде “разом” (наприклад, resource_id + published_at).

Тут важлива правильна думка: індекс — під запит, а не “на всяк випадок”. Якщо у вас є сторінка “контроль публікацій” з фільтрами по даті, користувачу і статусу — індекси мають відображати саме це. Інакше ви отримаєте повільні запити або повний скан таблиці. Але також не можна “наіндексувати все”, бо це збільшує розмір БД і уповільнює вставки/оновлення.

Складені індекси (composite) — коли індексуються кілька полів разом. Вони корисні, якщо ти майже завжди шукаєш по двох полях одночасно. Порядок полів в такому індексі має значення: база добре використовує індекс, коли фільтр починається з першого поля індексу. Тому індекси проектують не “як красиво”, а під реальні сценарії: які фільтри йдуть першими, які — додатковими.

Ще один критичний момент — унікальні індекси. Якщо поле повинно бути унікальним (slug, email, code), це треба фіксувати на рівні бази, а не тільки валідацією. Бо валідацію можна обійти або можна зловити гонку двох запитів. База — це остання лінія оборони. Унікальний індекс гарантує, що дубль фізично не запишеться.

Як зрозуміти, що міграції спроєктовані добре. Коли ти дивишся на таблицю, ти одразу бачиш: які поля обов’язкові, які можуть бути порожні, які мають дефолти, як таблиця пов’язана з іншими, і які індекси підтримують реальні списки/фільтри. Коли ти робиш новий модуль, тобі не треба “вигадувати” — ти додаєш за стандартом: foreign keys, індекси на фільтри, дефолти на статуси, nullable тільки по сенсу.

Практичний порядок роботи при додаванні нової таблиці завжди такий. Спочатку визначаєш сутність і поля: які обов’язкові. Потім визначаєш зв’язки: хто батько, хто дитина, що робити при видаленні. Потім визначаєш типові запити: як буде виглядати список, фільтри, сортування. І лише потім ставиш індекси під ці запити. Останнім кроком ставиш дефолти для стабільних станів і перевіряєш, чи nullable там, де треба, а не “де зручно”.

Висновок: міграції — це інженерна дисципліна, яка визначає стабільність і швидкість проєкту. Nullable — тільки там, де дозволяє сенс, дефолти — для початкових станів, foreign keys — для цілісності, індекси — для реальних запитів і фільтрів. Якщо ти закладеш ці правила з першого місяця, твій Laravel-проєкт не “посиплеться” на масштабі і не перетвориться на базу з випадковими даними.


Максим Третяк — Кореспондент, який спеціалізується на суспільно важливих темах, пише про політику, фінансові ринки та економіку. Він проживає та працює в Україні.

Цей матеріал є частиною розгорнутої теми: Web-програмування, яка охоплює численні цікаві аспекти цієї події. Газета «Дейком» ретельно відстежує події, проводячи перевірку джерел та інформації, щоб забезпечити нашим читачам найбільш точне та актуальне інформування.

Цей матеріал опубліковано 30.12.2025 року о 12:00 GMT+3 Київ; 05:00 GMT-4 Вашингтон, розділ: Освіта, із заголовком: "Міграції в Laravel: foreign keys, індекси, nullable та дефолти — як зробити схему правильно". Якщо в публікації з'являться зміни, про це буде зазначено та описано у кінці публікації.

Читайте щоденну газету та загальну стрічку новин газети Дейком, яка поєднує багато цікавого в понад 40 розділах з усіх куточків світу.


Save
ОГОЛОШЕННЯ

Новини, які можуть Вас зацікавити:

Штатні та позаштатні журналісти газети «Дейком» щодня готують сотні публікацій, щоб читачі отримували найоперативнішу, перевірену й глибоку інформацію. Ми працюємо для тих, хто хоче розуміти суть подій, бачити широку картину та бути на крок попереду.

Останні новини

Вибір редакції