18-bo‘lim

Migratsiyalar va sxema evolyutsiyasi

Migratsiya nima, versiya jadvali, oldinga va orqaga qadamlar, kengaytir-ko'chir-toraytir naqshi va nol to'xtovli o'zgarish.

🕑 20 daqiqa o‘qish 📄 1 251 so‘z 👁 1 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Nima uchun qo'lda ALTER yetarli emas
  2. Versiya jadvali
  3. Oldinga va orqaga
  4. Xavfli va xavfsiz o'zgarishlar
  5. Ustun nomini o'zgartirish - noto'g'ri yo'l
  6. Kengaytir - ko'chir - toraytir
  7. Katta jadvalda ALTER
  8. Ma'lumot migratsiyasi
  9. Migratsiya fayli namunasi
  10. Migratsiya va Git
  11. Xulosa

Sxema hech qachon tugallanmaydi - u ilova bilan birga o'sadi. Migratsiya - shu o'sishni boshqarish usuli.

Nima uchun qo'lda ALTER yetarli emas #

Bitta sxema - to'rt muhit Dasturchi 1 o'z kompyuteri Dasturchi 2 o'z kompyuteri Sinov serveri staging Ishlab chiqarish haqiqiy ma'lumot Migratsiya fayllari Git da saqlanadi, tartib bilan bajariladi Har muhit bir xil holatga keladi Kim, qachon, nima uchun - hammasi ko'rinadi
Qo'lda ALTER - to'rt muhitda to'rt xil sxema demakdir

Versiya jadvali #

SQL
CREATE TABLE migratsiyalar (
    versiya     VARCHAR(20) PRIMARY KEY,
    nomi        VARCHAR(200) NOT NULL,
    bajarilgan  DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);

INSERT INTO migratsiyalar (versiya, nomi, bajarilgan) VALUES
    ('20260101_0900', 'foydalanuvchilar jadvali', '2026-01-01 09:00:00'),
    ('20260115_1430', 'maqolalar jadvali',        '2026-01-15 14:30:00'),
    ('20260203_1000', 'maqolalarga rukn qoshish', '2026-02-03 10:00:00');
SQL
SELECT versiya, nomi, bajarilgan FROM migratsiyalar ORDER BY versiya;
Natija
+---------------+--------------------------+---------------------+
| versiya       | nomi                     | bajarilgan          |
+---------------+--------------------------+---------------------+
| 20260101_0900 | foydalanuvchilar jadvali | 2026-01-01 09:00:00 |
| 20260115_1430 | maqolalar jadvali        | 2026-01-15 14:30:00 |
| 20260203_1000 | maqolalarga rukn qoshish | 2026-02-03 10:00:00 |
+---------------+--------------------------+---------------------+
Versiya jadvali - migratsiya tizimining yuragi

Har migratsiya vositasi (Laravel, Doctrine, Flyway, Liquibase) shunday jadvalga ega. U bitta savolga javob beradi:

Qaysi migratsiyalar allaqachon bajarilgan?

Ishlash tartibi:

  1. Migratsiya papkasidagi barcha faylni o'qi;
  2. Jadvaldagi versiyalar bilan solishtir;
  3. Yo'qlarini tartib bilan bajar;
  4. Har birini jadvalga yoz.

Versiya nomlash usullari:

UsulMisolMuammosi
Ketma-ket son001, 002Ikki dasturchi bir xil raqam oladi
Vaqt tamg'asi20260101_0900Deyarli yo'q
UUIDa3f2...Tartib ko'rinmaydi

Vaqt tamg'asi eng yaxshi: ikki dasturchi bir vaqtda migratsiya yozsa ham, nomlar to'qnashmaydi va tartib aniq qoladi.

Oldinga va orqaga #

SQL
-- 20260210_1100_maqolalarga_korishlar_qoshish.sql
-- OLDINGA (up)

ALTER TABLE migratsiyalar ADD COLUMN izoh VARCHAR(500) NULL;

SELECT COLUMN_NAME AS ustun
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'migratsiyalar'
ORDER BY ORDINAL_POSITION;
Natija
+------------+
| ustun      |
+------------+
| versiya    |
| nomi       |
| bajarilgan |
| izoh       |
+------------+
SQL
-- ORQAGA (down) - o'zgarishni qaytarish
ALTER TABLE migratsiyalar ADD COLUMN izoh VARCHAR(500) NULL;
ALTER TABLE migratsiyalar DROP COLUMN izoh;

SELECT COUNT(*) AS ustunlar
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'migratsiyalar';
Natija
+----------+
| ustunlar |
+----------+
|        3 |
+----------+
down migratsiya - foydali, lekin ishonchsiz

Ko'p vosita har migratsiya uchun teskari qadamni ham talab qiladi:

PHP
public function up()   { $this->addColumn('izoh'); }
public function down() { $this->dropColumn('izoh'); }

Bu ishlab chiqishda foydali: notog'ri migratsiyani orqaga qaytarib, qayta yozish mumkin.

Lekin ishlab chiqarishda down ni ishlatish xavfli:

Amaldown da nima bo'ladi
ADD COLUMNDROP COLUMN - ma'lumot yo'qoladi
DROP TABLECREATE TABLE - bo'sh jadval
Ma'lumot ko'chirishKo'pincha qaytarib bo'lmaydi

Amaliyotda ishlab chiqarishda orqaga qaytarish o'rniga oldinga tuzatuvchi migratsiya yoziladi:

Natija
20260210_1100_notogri_ustun_qoshildi.sql
20260210_1145_notogri_ustunni_olib_tashlash.sql

Bu tarixni saqlaydi va nima bo'lganini ko'rsatadi.

Va 16-bo'limda ko'rganimizdek, MySQL/MariaDB da DDL tranzaksiyaga kirmaydi - yarim bajarilgan migratsiyani avtomatik qaytarib bo'lmaydi. Har qadamni alohida faylga ajrating.

Xavfli va xavfsiz o'zgarishlar #

O'zgarish turlari Xavfsiz Yangi jadval Yangi NULL ustun Yangi indeks (onlayn) DEFAULT qo'shish Ustunni kengaytirish Eski kod ishlashda davom etadi Ehtiyot bo'ling Katta jadvalga indeks Ustun turini o'zgartirish NOT NULL qo'shish Cheklov qo'shish Ma'lumot ko'chirish Uzoq ishlaydi, qulflashi mumkin Xavfli Ustunni o'chirish Ustun nomini o'zgartirish Jadvalni o'chirish Turni toraytirish Birlamchi kalitni o'zgartirish Eski kod QULAYDI Ma'lumot yo'qoladi
O'ng ustundagi o'zgarishlar bir necha bosqichda bajariladi

Ustun nomini o'zgartirish - noto'g'ri yo'l #

SQL
CREATE TABLE mijozlar (
    id      INT PRIMARY KEY AUTO_INCREMENT,
    tel     VARCHAR(20) NOT NULL,
    ism     VARCHAR(100) NOT NULL
);

INSERT INTO mijozlar (tel, ism) VALUES
    ('901234567', 'Husanboy'), ('911112233', 'Malika');
SQL
-- Bir qadamda nomni o'zgartirish
ALTER TABLE mijozlar CHANGE tel telefon VARCHAR(20) NOT NULL;

SELECT id, telefon, ism FROM mijozlar ORDER BY id;
Natija
+----+-----------+----------+
| id | telefon   | ism      |
+----+-----------+----------+
|  1 | 901234567 | Husanboy |
|  2 | 911112233 | Malika   |
+----+-----------+----------+
Bir qadamli o'zgartirish ishlab chiqarishni buzadi

Yuqoridagi ALTER ishladi, lekin ishlab chiqarishda u halokatga olib keladi.

Sabab - joylashtirish (deploy) bir lahzada bo'lmaydi:

Natija
Vaqt    Ma'lumotlar bazasi      Ilova serverlari
-----   ---------------------   ------------------------
10:00   tel ustuni              eski kod: SELECT tel
10:01   MIGRATSIYA -> telefon   eski kod: SELECT tel  <-- QULAYDI
10:02   telefon                 yangi kod: SELECT telefon

10:01 dan 10:02 gacha bo'lgan oraliqda eski kod hali ishlayapti, lekin ustun allaqachon yo'q.

Bu oraliq bir necha daqiqa davom etishi mumkin - ayniqsa bosqichma-bosqich joylashtirishda (rolling deploy).

Xuddi shu muammo:

  • Ustunni o'chirishda;
  • Jadval nomini o'zgartirishda;
  • Turni toraytirishda (VARCHAR(100)VARCHAR(20)).

Yechim - keyingi bo'limchadagi uch bosqichli naqsh.

Kengaytir - ko'chir - toraytir #

SQL
CREATE TABLE mijozlar_v2 (
    id   INT PRIMARY KEY AUTO_INCREMENT,
    tel  VARCHAR(20) NOT NULL,
    ism  VARCHAR(100) NOT NULL
);

INSERT INTO mijozlar_v2 (tel, ism) VALUES
    ('901234567', 'Husanboy'), ('911112233', 'Malika');
SQL
-- 1-BOSQICH: kengaytirish - yangi ustun qo'shamiz
ALTER TABLE mijozlar_v2 ADD COLUMN telefon VARCHAR(20) NULL;

-- 2-BOSQICH: ma'lumotni ko'chirish
UPDATE mijozlar_v2 SET telefon = tel WHERE telefon IS NULL;

SELECT id, tel, telefon FROM mijozlar_v2 ORDER BY id;
Natija
+----+-----------+-----------+
| id | tel       | telefon   |
+----+-----------+-----------+
|  1 | 901234567 | 901234567 |
|  2 | 911112233 | 911112233 |
+----+-----------+-----------+
SQL
-- (1 va 2-bosqich takrorlangan - har misol toza bazada ishlaydi)
ALTER TABLE mijozlar_v2 ADD COLUMN telefon VARCHAR(20) NULL;
UPDATE mijozlar_v2 SET telefon = tel WHERE telefon IS NULL;

-- 3-BOSQICH: eski ustunni olib tashlash (kod yangilangandan KEYIN)
ALTER TABLE mijozlar_v2 DROP COLUMN tel;
ALTER TABLE mijozlar_v2 MODIFY telefon VARCHAR(20) NOT NULL;

SELECT COLUMN_NAME AS ustun, IS_NULLABLE AS null_mumkinmi
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'mijozlar_v2'
ORDER BY ORDINAL_POSITION;
Natija
+---------+---------------+
| ustun   | null_mumkinmi |
+---------+---------------+
| id      | NO            |
| ism     | NO            |
| telefon | NO            |
+---------+---------------+
Uch bosqich - nol to'xtovli o'zgarish

Bu naqsh expand-migrate-contract deb ataladi va deyarli har qanday xavfli o'zgarishga qo'llanadi.

Har bosqich alohida joylashtirish bo'ladi:

BosqichMigratsiyaIlova kodi
1. KengaytirishYangi ustun qo'shishO'zgarmaydi
2. Ikki tomonlama yozish-Ikkalasiga yozadi
3. Ko'chirishEski ma'lumotni nusxalashO'zgarmaydi
4. O'qishni ko'chirish-Yangisidan o'qiydi
5. ToraytirishEski ustunni o'chirishO'zgarmaydi

Har bosqichda tizim ishlab turadi va istalgan paytda orqaga qaytish mumkin.

Bu ko'p ish - lekin muqobili rejalashtirilgan to'xtash yoki buzilgan xizmat.

Kichik loyihalarda (kechasi bir necha daqiqa to'xtash mumkin bo'lsa) bir qadamli ALTER ham maqbul. Qaror xizmat talabiga bog'liq.

Katta jadvalda ALTER #

SQL
SELECT
    TABLE_NAME AS jadval,
    TABLE_ROWS AS taxminiy_qatorlar,
    ROUND(DATA_LENGTH / 1024 / 1024, 2) AS malumot_mb
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'mijozlar'
ORDER BY TABLE_NAME;
Natija
+----------+-------------------+------------+
| jadval   | taxminiy_qatorlar | malumot_mb |
+----------+-------------------+------------+
| mijozlar |                 2 |       0.02 |
+----------+-------------------+------------+
Million qatorli jadvalda ALTER soatlab ishlaydi

MySQL 5.6 va MariaDB 10.0 dan boshlab ko'p ALTER amallari onlayn bajariladi - jadval qulflanmaydi.

Lekin hammasi emas:

AmalOnlaynmiJadval qayta quriladimi
ADD INDEXHaYo'q
DROP INDEXHaYo'q
ADD COLUMN (oxiriga)HaHa (eski versiyalarda)
MODIFY turni o'zgartirishYo'qHa
ADD PRIMARY KEYYo'qHa
Charset o'zgartirishYo'qHa

"Qayta quriladi" degani - jadvalning to'liq nusxasi yaratiladi. 100 GB jadvalda bu 100 GB bo'sh joy va soatlab vaqt talab qiladi.

Rejani oldindan ko'rish:

SQL
ALTER TABLE katta_jadval ADD COLUMN yangi INT,
    ALGORITHM = INPLACE, LOCK = NONE;

Agar bu variant qo'llab-quvvatlanmasa, MariaDB xato beradi - ya'ni siz tasodifan jadvalni qulflab qo'ymaysiz.

Juda katta jadvallar uchun tashqi vositalar ishlatiladi:

VositaIshlash usuli
pt-online-schema-changeNusxa + trigger + almashtirish
gh-ostBinlog o'qish, triggersiz

Ular jadvalni bo'lak-bo'lak ko'chiradi va yukni boshqaradi.

Ma'lumot migratsiyasi #

SQL
CREATE TABLE foydalanuvchilar (
    id        INT PRIMARY KEY AUTO_INCREMENT,
    toliq_ism VARCHAR(200) NOT NULL
);

INSERT INTO foydalanuvchilar (toliq_ism) VALUES
    ('Husanboy Qodirov'), ('Malika Yusupova'), ('Kamola');
SQL
-- Ismni ikki ustunga ajratamiz
ALTER TABLE foydalanuvchilar
    ADD COLUMN ism      VARCHAR(100) NULL,
    ADD COLUMN familiya VARCHAR(100) NULL;

UPDATE foydalanuvchilar
SET ism      = SUBSTRING_INDEX(toliq_ism, ' ', 1),
    familiya = CASE
                   WHEN LOCATE(' ', toliq_ism) > 0
                   THEN SUBSTRING(toliq_ism, LOCATE(' ', toliq_ism) + 1)
                   ELSE NULL
               END;

SELECT id, toliq_ism, ism, COALESCE(familiya, '(yoq)') AS familiya
FROM foydalanuvchilar
ORDER BY id;
Natija
+----+------------------+----------+----------+
| id | toliq_ism        | ism      | familiya |
+----+------------------+----------+----------+
|  1 | Husanboy Qodirov | Husanboy | Qodirov  |
|  2 | Malika Yusupova  | Malika   | Yusupova |
|  3 | Kamola           | Kamola   | (yoq)    |
+----+------------------+----------+----------+
Ma'lumot migratsiyasini avval sinab ko'ring

Yuqoridagi ajratish oddiy ko'rinadi, lekin haqiqiy ma'lumotda kutilmagan holatlar bo'ladi:

KirishNatijaTo'g'rimi
'Husanboy Qodirov'Husanboy + QodirovHa
'Kamola'Kamola + NULLEhtimol
'Qodirov Husanboy Baxtiyor o''g''li'Qodirov + qolganiChalkash
' Malika '` +Malika`Xato
''` +NULL`Xato

Shuning uchun ma'lumot migratsiyasidan oldin:

1. Ma'lumotni tekshiring:

SQL
SELECT COUNT(*) AS bosh          FROM foydalanuvchilar WHERE TRIM(toliq_ism) = '';
SELECT COUNT(*) AS bir_sozli     FROM foydalanuvchilar WHERE LOCATE(' ', toliq_ism) = 0;
SELECT COUNT(*) AS uch_va_kop    FROM foydalanuvchilar
WHERE LENGTH(toliq_ism) - LENGTH(REPLACE(toliq_ism, ' ', '')) >= 2;

2. Nusxada sinab ko'ring - ishlab chiqarish nusxasida.

3. Eski ustunni darhol o'chirmang - bir necha hafta qoldiring, natijani tekshiring.

4. Katta jadvalda bo'lak-bo'lak yangilang:

SQL
UPDATE foydalanuvchilar SET ... WHERE id BETWEEN 1 AND 10000;
UPDATE foydalanuvchilar SET ... WHERE id BETWEEN 10001 AND 20000;

Bitta katta UPDATE uzun tranzaksiya yaratadi va replikatsiyani kechiktiradi (17-bo'lim).

Migratsiya fayli namunasi #

SQL
-- 20260315_1400_maqolalarga_korishlar_qoshish.sql
--
-- Maqsad: maqola necha marta ko'rilganini saqlash
-- Muallif: Husanboy Qodirov
-- Xavflilik: past (yangi ustun, DEFAULT bilan)
-- Taxminiy vaqt: < 1 soniya (jadvalda ~5000 qator)

ALTER TABLE maqolalar
    ADD COLUMN korishlar INT UNSIGNED NOT NULL DEFAULT 0;

CREATE INDEX idx_maqola_korishlar ON maqolalar (korishlar DESC);

-- Tekshiruv:
--   SELECT COUNT(*) FROM maqolalar WHERE korishlar IS NULL;  -> 0 bo'lishi kerak
Migratsiya faylida nima bo'lishi kerak
ElementNima uchun
MaqsadKeyingi dasturchi nima uchunligini tushunsin
MuallifSavol paydo bo'lsa kimga murojaat qilish
XavflilikKim tekshirishi kerakligini bildiradi
Taxminiy vaqtJoylashtirish rejasi uchun
Tekshiruv so'roviMigratsiya to'g'ri o'tganini isbotlash

Oxirgisi ko'pincha unutiladi. Migratsiya "xatosiz o'tdi" degani to'g'ri natija berdi degani emas.

Yana bir muhim qoida: migratsiya faylini o'zgartirmang.

U bir marta bajarilgach, boshqa muhitlarda ham bajarilgan bo'ladi. Uni tahrirlash sxemalarni bir-biridan ajratadi.

Xato topsangiz - yangi migratsiya yozing.

Migratsiya va Git #

Sxema kodning bir qismi

Migratsiya fayllari kod bilan birga Git da saqlanadi va bir xil qoidalarga bo'ysunadi:

QoidaIzoh
Kod bilan bir commit daSxema va kod mos keladi
Code review dan o'tadiXavfli o'zgarish tutiladi
CI da sinab ko'riladiBo'sh bazada ishlashi tekshiriladi
Hech qachon tahrirlanmaydiFaqat yangisi qo'shiladi

CI da tekshirish oddiy:

Terminal
# Bo'sh bazaga barcha migratsiyani qo'llash
mysql -e "CREATE DATABASE sinov;"
for f in migrations/*.sql; do
    mysql sinov < "$f" || exit 1
done

Bu "birinchi kundan boshlab" ishlashini kafolatlaydi - yangi dasturchi loyihani bir buyruq bilan ko'tara oladi.

Bu loyihaning database/migrations/ papkasi ham xuddi shu naqshga amal qiladi.

Amaliy topshiriq
  1. Versiya jadvalini yarating va uch yozuv qo'shing.
  2. Vaqt tamg'asi nima uchun ketma-ket sondan afzalligini ayting.
  3. up va down migratsiyasini yozing.
  4. down ni ishlab chiqarishda ishlatish xavfini tushuntiring.
  5. Ustun nomini bir qadamda o'zgartiring.
  6. Nima uchun bu ishlab chiqarishni buzishini ayting.
  7. Kengaytir-ko'chir-toraytir naqshini uch qadamda bajaring.
  8. Qaysi ALTER amallari jadvalni qayta qurishini sanang.
  9. Ismni ikki ustunga ajratib, chekka holatlarni toping.
  10. To'liq migratsiya faylini izohlar bilan yozing.

Xulosa #

  • Migratsiya - sxema o'zgarishini kod kabi boshqarish.
  • Versiya jadvali qaysi migratsiya bajarilganini saqlaydi.
  • Versiya nomida vaqt tamg'asi ishlating.
  • down ishlab chiqishda foydali, ishlab chiqarishda xavfli.
  • Xato bo'lsa - oldinga tuzatuvchi migratsiya yozing.
  • Ustun nomini bir qadamda o'zgartirish xizmatni buzadi.
  • Kengaytir → ko'chir → toraytir - nol to'xtovli naqsh.
  • Katta jadvalda ALTER jadvalni qayta qurishi mumkin.
  • ALGORITHM = INPLACE, LOCK = NONE bilan oldindan tekshiring.
  • Ma'lumot migratsiyasini nusxada sinab ko'ring.
  • Katta yangilanishni bo'lak-bo'lak bajaring.
  • Migratsiya faylini hech qachon tahrirlamang.

Keyingi bo'limda ma'lumotlar bazasi xavfsizligini ko'ramiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.