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.
Ushbu bo‘lim mundarijasi
Sxema hech qachon tugallanmaydi - u ilova bilan birga o'sadi. Migratsiya - shu o'sishni boshqarish usuli.
Nima uchun qo'lda ALTER yetarli emas #
Versiya jadvali #
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');
SELECT versiya, nomi, bajarilgan FROM migratsiyalar ORDER BY versiya;
+---------------+--------------------------+---------------------+
| 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 |
+---------------+--------------------------+---------------------+
Har migratsiya vositasi (Laravel, Doctrine, Flyway, Liquibase) shunday jadvalga ega. U bitta savolga javob beradi:
Qaysi migratsiyalar allaqachon bajarilgan?
Ishlash tartibi:
- Migratsiya papkasidagi barcha faylni o'qi;
- Jadvaldagi versiyalar bilan solishtir;
- Yo'qlarini tartib bilan bajar;
- Har birini jadvalga yoz.
Versiya nomlash usullari:
| Usul | Misol | Muammosi |
|---|---|---|
| Ketma-ket son | 001, 002 | Ikki dasturchi bir xil raqam oladi |
| Vaqt tamg'asi | 20260101_0900 | Deyarli yo'q |
| UUID | a3f2... | 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 #
-- 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;
+------------+
| ustun |
+------------+
| versiya |
| nomi |
| bajarilgan |
| izoh |
+------------+
-- 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';
+----------+
| ustunlar |
+----------+
| 3 |
+----------+
down migratsiya - foydali, lekin ishonchsizKo'p vosita har migratsiya uchun teskari qadamni ham talab qiladi:
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:
| Amal | down da nima bo'ladi |
|---|---|
ADD COLUMN | DROP COLUMN - ma'lumot yo'qoladi |
DROP TABLE | CREATE TABLE - bo'sh jadval |
| Ma'lumot ko'chirish | Ko'pincha qaytarib bo'lmaydi |
Amaliyotda ishlab chiqarishda orqaga qaytarish o'rniga oldinga tuzatuvchi migratsiya yoziladi:
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 #
Ustun nomini o'zgartirish - noto'g'ri yo'l #
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');
-- Bir qadamda nomni o'zgartirish
ALTER TABLE mijozlar CHANGE tel telefon VARCHAR(20) NOT NULL;
SELECT id, telefon, ism FROM mijozlar ORDER BY id;
+----+-----------+----------+
| id | telefon | ism |
+----+-----------+----------+
| 1 | 901234567 | Husanboy |
| 2 | 911112233 | Malika |
+----+-----------+----------+
Yuqoridagi ALTER ishladi, lekin ishlab chiqarishda u
halokatga olib keladi.
Sabab - joylashtirish (deploy) bir lahzada bo'lmaydi:
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 #
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');
-- 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;
+----+-----------+-----------+
| id | tel | telefon |
+----+-----------+-----------+
| 1 | 901234567 | 901234567 |
| 2 | 911112233 | 911112233 |
+----+-----------+-----------+
-- (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;
+---------+---------------+
| ustun | null_mumkinmi |
+---------+---------------+
| id | NO |
| ism | NO |
| telefon | NO |
+---------+---------------+
Bu naqsh expand-migrate-contract deb ataladi va deyarli har qanday xavfli o'zgarishga qo'llanadi.
Har bosqich alohida joylashtirish bo'ladi:
| Bosqich | Migratsiya | Ilova kodi |
|---|---|---|
| 1. Kengaytirish | Yangi ustun qo'shish | O'zgarmaydi |
| 2. Ikki tomonlama yozish | - | Ikkalasiga yozadi |
| 3. Ko'chirish | Eski ma'lumotni nusxalash | O'zgarmaydi |
| 4. O'qishni ko'chirish | - | Yangisidan o'qiydi |
| 5. Toraytirish | Eski ustunni o'chirish | O'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 #
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;
+----------+-------------------+------------+
| jadval | taxminiy_qatorlar | malumot_mb |
+----------+-------------------+------------+
| mijozlar | 2 | 0.02 |
+----------+-------------------+------------+
ALTER soatlab ishlaydiMySQL 5.6 va MariaDB 10.0 dan boshlab ko'p ALTER amallari
onlayn bajariladi - jadval qulflanmaydi.
Lekin hammasi emas:
| Amal | Onlaynmi | Jadval qayta quriladimi |
|---|---|---|
ADD INDEX | Ha | Yo'q |
DROP INDEX | Ha | Yo'q |
ADD COLUMN (oxiriga) | Ha | Ha (eski versiyalarda) |
MODIFY turni o'zgartirish | Yo'q | Ha |
ADD PRIMARY KEY | Yo'q | Ha |
| Charset o'zgartirish | Yo'q | Ha |
"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:
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:
| Vosita | Ishlash usuli |
|---|---|
pt-online-schema-change | Nusxa + trigger + almashtirish |
gh-ost | Binlog o'qish, triggersiz |
Ular jadvalni bo'lak-bo'lak ko'chiradi va yukni boshqaradi.
Ma'lumot migratsiyasi #
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');
-- 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;
+----+------------------+----------+----------+
| id | toliq_ism | ism | familiya |
+----+------------------+----------+----------+
| 1 | Husanboy Qodirov | Husanboy | Qodirov |
| 2 | Malika Yusupova | Malika | Yusupova |
| 3 | Kamola | Kamola | (yoq) |
+----+------------------+----------+----------+
Yuqoridagi ajratish oddiy ko'rinadi, lekin haqiqiy ma'lumotda kutilmagan holatlar bo'ladi:
| Kirish | Natija | To'g'rimi |
|---|---|---|
'Husanboy Qodirov' | Husanboy + Qodirov | Ha |
'Kamola' | Kamola + NULL | Ehtimol |
'Qodirov Husanboy Baxtiyor o''g''li' | Qodirov + qolgani | Chalkash |
' Malika ' | ` +Malika` | Xato |
'' | ` +NULL` | Xato |
Shuning uchun ma'lumot migratsiyasidan oldin:
1. Ma'lumotni tekshiring:
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:
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 #
-- 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
| Element | Nima uchun |
|---|---|
| Maqsad | Keyingi dasturchi nima uchunligini tushunsin |
| Muallif | Savol paydo bo'lsa kimga murojaat qilish |
| Xavflilik | Kim tekshirishi kerakligini bildiradi |
| Taxminiy vaqt | Joylashtirish rejasi uchun |
| Tekshiruv so'rovi | Migratsiya 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 #
Migratsiya fayllari kod bilan birga Git da saqlanadi va bir xil qoidalarga bo'ysunadi:
| Qoida | Izoh |
|---|---|
| Kod bilan bir commit da | Sxema va kod mos keladi |
| Code review dan o'tadi | Xavfli o'zgarish tutiladi |
| CI da sinab ko'riladi | Bo'sh bazada ishlashi tekshiriladi |
| Hech qachon tahrirlanmaydi | Faqat yangisi qo'shiladi |
CI da tekshirish oddiy:
# 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.
- Versiya jadvalini yarating va uch yozuv qo'shing.
- Vaqt tamg'asi nima uchun ketma-ket sondan afzalligini ayting.
upvadownmigratsiyasini yozing.downni ishlab chiqarishda ishlatish xavfini tushuntiring.- Ustun nomini bir qadamda o'zgartiring.
- Nima uchun bu ishlab chiqarishni buzishini ayting.
- Kengaytir-ko'chir-toraytir naqshini uch qadamda bajaring.
- Qaysi
ALTERamallari jadvalni qayta qurishini sanang. - Ismni ikki ustunga ajratib, chekka holatlarni toping.
- 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.
downishlab 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
ALTERjadvalni qayta qurishi mumkin. ALGORITHM = INPLACE, LOCK = NONEbilan 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.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
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.