15-bo‘lim
Normalizatsiya va loyihalash
Anomaliyalar, 1NF, 2NF, 3NF normal shakllari, denormalizatsiya va ER-diagramma tuzish.
Ushbu bo‘lim mundarijasi
- Muammo: yomon loyihalangan jadval
- Birinchi normal shakl (1NF)
- Ikkinchi normal shakl (2NF)
- Uchinchi normal shakl (3NF)
- Denormalizatsiya
- Boshqa denormalizatsiya holatlari
- Loyihalash jarayoni
- 1-qadam: obyektlarni aniqlash
- 2-qadam: xususiyatlarni yozish
- 3-qadam: bog'lanishlarni aniqlash
- 4-qadam: normalizatsiya qilish
- 5-qadam: kalit va indekslarni qo'yish
- To'liq sxema misoli
- Loyihalash tekshiruv ro'yxati
- Nomlash kelishuvlari
- Xulosa
Normalizatsiya - jadvallarni takrorlanishsiz va xatosiz tashkil qilish usuli. U bazaning uzoq muddatli sog'lig'ini ta'minlaydi.
Muammo: yomon loyihalangan jadval #
CREATE TABLE buyurtmalar_yomon (
id INT PRIMARY KEY,
mijoz_ism VARCHAR(120),
mijoz_telefon VARCHAR(20),
mijoz_shahar VARCHAR(60),
mahsulotlar VARCHAR(500), -- "Klaviatura, Sichqoncha, Monitor"
narxlar VARCHAR(200), -- "185000, 95000, 2450000"
jami DECIMAL(12,2)
);
Bu jadval uch xil anomaliyaga olib keladi:
| Anomaliya | Misol |
|---|---|
| Qo'shish | Buyurtma bermagan mijozni saqlab bo'lmaydi |
| Yangilash | Telefon o'zgarsa - 50 ta qatorda o'zgartirish kerak |
| O'chirish | Oxirgi buyurtma o'chsa - mijoz ma'lumoti ham yo'qoladi |
Birinchi normal shakl (1NF) #
Har bir katakda bitta qiymat bo'lsin. Takrorlanuvchi guruhlar bo'lmasin.
-- 1NF BUZILGAN: bitta katakda ko'p qiymat
| id | mijoz | mahsulotlar |
| 1 | Husanboy | Klaviatura, Sichqoncha, Monitor |
-- 1NF: har bir qiymat alohida qatorda
CREATE TABLE buyurtma_elementlari (
buyurtma_id INT UNSIGNED,
mahsulot VARCHAR(160),
narx DECIMAL(12,2),
soni SMALLINT UNSIGNED
);
| buyurtma_id | mahsulot | narx | soni |
| 1 | Klaviatura | 185000 | 1 |
| 1 | Sichqoncha | 95000 | 2 |
| 1 | Monitor | 2450000 | 1 |
teglar VARCHAR(255) -- "python, algoritm, backend"
Bu qulay tuyuladi, lekin:
WHERE teglar = 'python'ishlamaydiLIKE '%python%'"python3" ni ham topadi- Indeks ishlamaydi
- Teg nomini o'zgartirish uchun barcha qatorlarni tahrirlash kerak
To'g'ri yechim - alohida jadval:
CREATE TABLE teglar (id INT PRIMARY KEY, nomi VARCHAR(60) UNIQUE);
CREATE TABLE maqola_teg (maqola_id INT, teg_id INT, PRIMARY KEY (maqola_id, teg_id));
Ikkinchi normal shakl (2NF) #
1NF bajarilsin va har bir ustun butun birlamchi kalitga bog'liq bo'lsin.
Bu qoida faqat tarkibiy kalit bo'lganda muhim:
-- 2NF BUZILGAN
CREATE TABLE talaba_fan_yomon (
talaba_id INT,
fan_id INT,
baho TINYINT,
talaba_ism VARCHAR(120), -- faqat talaba_id ga bog'liq!
fan_nomi VARCHAR(120), -- faqat fan_id ga bog'liq!
PRIMARY KEY (talaba_id, fan_id)
);
talaba_ism faqat kalitning yarmiga bog'liq. Natijada talaba nomi har bir fan uchun takrorlanadi.
-- 2NF: to'g'ri bo'lingan
CREATE TABLE talabalar (
id INT UNSIGNED PRIMARY KEY,
ism VARCHAR(120) NOT NULL
);
CREATE TABLE fanlar (
id INT UNSIGNED PRIMARY KEY,
nomi VARCHAR(120) NOT NULL
);
CREATE TABLE talaba_fan (
talaba_id INT UNSIGNED,
fan_id INT UNSIGNED,
baho TINYINT,
PRIMARY KEY (talaba_id, fan_id)
);
Uchinchi normal shakl (3NF) #
2NF bajarilsin va ustunlar bir-biriga bog'liq bo'lmasin (faqat kalitga).
-- 3NF BUZILGAN
CREATE TABLE talabalar_yomon (
id INT PRIMARY KEY,
ism VARCHAR(120),
guruh_id INT,
guruh_nomi VARCHAR(20), -- guruh_id ga bog'liq, id ga emas!
guruh_yili YEAR -- bu ham
);
guruh_nomi id ga emas, guruh_id ga bog'liq. Bu tranzitiv bog'liqlik.
-- 3NF: to'g'ri
CREATE TABLE guruhlar (
id INT UNSIGNED PRIMARY KEY,
nomi VARCHAR(20) NOT NULL,
yil YEAR NOT NULL
);
CREATE TABLE talabalar (
id INT UNSIGNED PRIMARY KEY,
ism VARCHAR(120) NOT NULL,
guruh_id INT UNSIGNED,
FOREIGN KEY (guruh_id) REFERENCES guruhlar (id)
);
Har bir ustun kalitga, butun kalitga va faqat kalitga bog'liq bo'lsin.
- "kalitga" → 1NF
- "butun kalitga" → 2NF
- "faqat kalitga" → 3NF
Amalda 3NF yetarli. Undan yuqori shakllar (BCNF, 4NF, 5NF) nazariy jihatdan mavjud, lekin real loyihalarda kamdan-kam kerak bo'ladi.
Denormalizatsiya #
Ba'zan ataylab normalizatsiya qoidasini buzish kerak bo'ladi.
-- Buyurtmada sotib olish paytidagi narx saqlanadi
CREATE TABLE buyurtma_elementlari (
buyurtma_id INT UNSIGNED,
mahsulot_id INT UNSIGNED,
soni SMALLINT UNSIGNED,
narx DECIMAL(12,2) -- takrorlanish, lekin ZARUR
);
Mahsulot narxi bugun 185 000, kelasi oy 210 000 bo'lishi mumkin. Agar buyurtmada
faqat mahsulot_id saqlansa, eski chekni ochganda yangi narx ko'rinadi -
bu buxgalteriya nuqtai nazaridan xato.
Bu tarixiy ma'lumot deb ataladi va normalizatsiyadan asosli chetlashish.
Boshqa denormalizatsiya holatlari #
-- Hisoblangan qiymatni saqlash (tez o'qish uchun)
CREATE TABLE maqolalar (
id INT UNSIGNED PRIMARY KEY,
sarlavha VARCHAR(200),
izohlar_soni INT UNSIGNED DEFAULT 0 -- COUNT o'rniga
);
-- Har bir izoh qo'shilganda yangilanadi
UPDATE maqolalar SET izohlar_soni = izohlar_soni + 1 WHERE id = ?;
| Denormalizatsiya | Qachon oqlanadi |
|---|---|
| Tarixiy narx | Har doim |
Hisoblangan qiymat (COUNT) | O'qish yozishdan ancha ko'p bo'lsa |
| Takrorlangan nom | Juda katta hisobotlarda |
| Yig'ma jadval | Analitika uchun |
Avval normal loyihalang. Keyin o'lchang. Sekin bo'lsa - indeks qo'ying. Baribir sekin bo'lsa - shundagina denormalizatsiya haqida o'ylang.
Erta denormalizatsiya - ma'lumot nomuvofiqligining eng keng tarqalgan sababi.
Loyihalash jarayoni #
1-qadam: obyektlarni aniqlash #
Tizimda qanday "narsalar" bor?
Onlayn do'kon:
- Mijoz
- Mahsulot
- Kategoriya
- Buyurtma
- Yetkazib beruvchi
- Sharh
2-qadam: xususiyatlarni yozish #
Mahsulot: nomi, tavsif, narx, ombordagi soni, rasm, kategoriya
Buyurtma: mijoz, sana, holat, yetkazish manzili, jami summa
3-qadam: bog'lanishlarni aniqlash #
Mijoz --< Buyurtma (1:N)
Buyurtma >--< Mahsulot (N:M, oraliq jadval bilan)
Kategoriya --< Mahsulot (1:N)
Mijoz --< Sharh >-- Mahsulot (N:M)
4-qadam: normalizatsiya qilish #
Har bir jadvalni 3NF ga keltiring.
5-qadam: kalit va indekslarni qo'yish #
PRIMARY KEY, FOREIGN KEY, UNIQUE, INDEX
To'liq sxema misoli #
CREATE DATABASE dokon CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE dokon;
CREATE TABLE kategoriyalar (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
ota_id INT UNSIGNED NULL,
nomi VARCHAR(80) NOT NULL,
slug VARCHAR(100) NOT NULL UNIQUE,
FOREIGN KEY (ota_id) REFERENCES kategoriyalar (id) ON DELETE SET NULL
) ENGINE=InnoDB;
CREATE TABLE mahsulotlar (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
kategoriya_id INT UNSIGNED NOT NULL,
nomi VARCHAR(160) NOT NULL,
slug VARCHAR(180) NOT NULL UNIQUE,
tavsif TEXT,
narx DECIMAL(12,2) NOT NULL,
ombor INT UNSIGNED NOT NULL DEFAULT 0,
faolmi BOOLEAN NOT NULL DEFAULT TRUE,
yaratilgan TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (kategoriya_id) REFERENCES kategoriyalar (id) ON DELETE RESTRICT,
KEY idx_kategoriya (kategoriya_id, faolmi),
KEY idx_narx (narx)
) ENGINE=InnoDB;
CREATE TABLE mijozlar (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
ism VARCHAR(120) NOT NULL,
email VARCHAR(190) NOT NULL UNIQUE,
telefon VARCHAR(20),
yaratilgan TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
CREATE TABLE manzillar (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
mijoz_id INT UNSIGNED NOT NULL,
shahar VARCHAR(60) NOT NULL,
kocha VARCHAR(160) NOT NULL,
asosiymi BOOLEAN NOT NULL DEFAULT FALSE,
FOREIGN KEY (mijoz_id) REFERENCES mijozlar (id) ON DELETE CASCADE,
KEY idx_mijoz (mijoz_id)
) ENGINE=InnoDB;
CREATE TABLE buyurtmalar (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
mijoz_id INT UNSIGNED NOT NULL,
manzil_id INT UNSIGNED,
holat ENUM('yangi','tolangan','yigilmoqda','yolda','yetkazildi','bekor')
NOT NULL DEFAULT 'yangi',
jami DECIMAL(12,2) NOT NULL DEFAULT 0,
yaratilgan TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (mijoz_id) REFERENCES mijozlar (id) ON DELETE RESTRICT,
FOREIGN KEY (manzil_id) REFERENCES manzillar (id) ON DELETE SET NULL,
KEY idx_mijoz (mijoz_id),
KEY idx_holat (holat, yaratilgan)
) ENGINE=InnoDB;
CREATE TABLE buyurtma_elementlari (
buyurtma_id INT UNSIGNED NOT NULL,
mahsulot_id INT UNSIGNED NOT NULL,
soni SMALLINT UNSIGNED NOT NULL DEFAULT 1,
narx DECIMAL(12,2) NOT NULL, -- tarixiy narx
PRIMARY KEY (buyurtma_id, mahsulot_id),
FOREIGN KEY (buyurtma_id) REFERENCES buyurtmalar (id) ON DELETE CASCADE,
FOREIGN KEY (mahsulot_id) REFERENCES mahsulotlar (id) ON DELETE RESTRICT
) ENGINE=InnoDB;
CREATE TABLE sharhlar (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
mahsulot_id INT UNSIGNED NOT NULL,
mijoz_id INT UNSIGNED NOT NULL,
reyting TINYINT UNSIGNED NOT NULL CHECK (reyting BETWEEN 1 AND 5),
matn TEXT,
yaratilgan TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uq_mijoz_mahsulot (mijoz_id, mahsulot_id), -- bitta sharh
FOREIGN KEY (mahsulot_id) REFERENCES mahsulotlar (id) ON DELETE CASCADE,
FOREIGN KEY (mijoz_id) REFERENCES mijozlar (id) ON DELETE CASCADE,
KEY idx_mahsulot (mahsulot_id, reyting)
) ENGINE=InnoDB;
Loyihalash tekshiruv ro'yxati #
| Savol | Tekshirish |
|---|---|
| Har bir jadvalda PK bormi? | DESCRIBE |
| Barcha FK belgilanganmi? | SHOW CREATE TABLE |
| Ma'lumot takrorlanmayaptimi? | Sxemani ko'zdan kechirish |
| Katakda vergulli ro'yxat yo'qmi? | Ustunlar turini tekshirish |
Pul DECIMAL da saqlanyaptimi? | DESCRIBE |
NOT NULL to'g'ri qo'yilganmi? | Mantiqiy tekshiruv |
UNIQUE kerakli joydami? | email, slug, kod |
JOIN ustunlarida indeks bormi? | SHOW INDEX |
yaratilgan/yangilangan bormi? | DESCRIBE |
| Nomlar izchilmi? | mijoz_id, mahsulot_id - bir uslubda |
Nomlash kelishuvlari #
| Element | Uslub | Misol |
|---|---|---|
| Jadval | ko'plik, kichik harf | mahsulotlar |
| Ustun | kichik harf, _ | yaratilgan_sana |
| Birlamchi kalit | id | id |
| Tashqi kalit | <jadval_birlik>_id | mijoz_id |
| Oraliq jadval | ikkala nom | buyurtma_elementlari |
| Indeks | idx_ | idx_shahar |
| Noyob indeks | uq_ | uq_email |
| Tashqi kalit | fk_ | fk_buyurtma_mijoz |
Quyidagi yomon jadvalni 3NF ga keltiring:
CREATE TABLE kurslar_yomon (
id INT,
talaba_ism VARCHAR(120),
talaba_email VARCHAR(190),
talaba_shahar VARCHAR(60),
kurs_nomi VARCHAR(120),
kurs_narxi DECIMAL(10,2),
oqituvchi_ism VARCHAR(120),
oqituvchi_tel VARCHAR(20),
baholar VARCHAR(100), -- "5, 4, 5, 3"
tolov_sanasi DATE
);
- 1NF buzilgan joyni toping va tuzating.
- Qanday obyektlar bor? Ularni sanang.
- Har biri uchun alohida jadval yarating.
- Bog'lanishlarni aniqlang va tashqi kalitlar qo'ying.
- Kerakli indekslarni qo'shing.
CREATE TABLEso'rovlarini yozing.- Sxemani qog'ozda chizing.
- Sinov ma'lumoti qo'shib, bir nechta
JOINso'rovi yozing.
Xulosa #
- Normalizatsiya qo'shish, yangilash va o'chirish anomaliyalarini yo'q qiladi.
- 1NF: har bir katakda bitta qiymat; vergulli ro'yxat - eng ko'p uchraydigan xato.
- 2NF: har bir ustun butun tarkibiy kalitga bog'liq.
- 3NF: ustunlar bir-biriga emas, faqat kalitga bog'liq.
- Amalda 3NF yetarli.
- Denormalizatsiya ataylab qilinadi: tarixiy narx, hisoblangan qiymatlar.
- Avval to'g'ri loyihalang, keyin o'lchang, so'ng optimallashtiring.
- Izchil nomlash kelishuvi kodni ancha o'qishli qiladi.
Keyingi bo'limda tranzaksiyalarni o'rganamiz.
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.