15-bo‘lim

Normalizatsiya va loyihalash

Anomaliyalar, 1NF, 2NF, 3NF normal shakllari, denormalizatsiya va ER-diagramma tuzish.

🕑 12 daqiqa o‘qish 📄 783 so‘z 👁 5 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Muammo: yomon loyihalangan jadval
  2. Birinchi normal shakl (1NF)
  3. Ikkinchi normal shakl (2NF)
  4. Uchinchi normal shakl (3NF)
  5. Denormalizatsiya
  6. Boshqa denormalizatsiya holatlari
  7. Loyihalash jarayoni
  8. 1-qadam: obyektlarni aniqlash
  9. 2-qadam: xususiyatlarni yozish
  10. 3-qadam: bog'lanishlarni aniqlash
  11. 4-qadam: normalizatsiya qilish
  12. 5-qadam: kalit va indekslarni qo'yish
  13. To'liq sxema misoli
  14. Loyihalash tekshiruv ro'yxati
  15. Nomlash kelishuvlari
  16. Xulosa

Normalizatsiya - jadvallarni takrorlanishsiz va xatosiz tashkil qilish usuli. U bazaning uzoq muddatli sog'lig'ini ta'minlaydi.

Muammo: yomon loyihalangan jadval #

SQL
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:

AnomaliyaMisol
Qo'shishBuyurtma bermagan mijozni saqlab bo'lmaydi
YangilashTelefon o'zgarsa - 50 ta qatorda o'zgartirish kerak
O'chirishOxirgi buyurtma o'chsa - mijoz ma'lumoti ham yo'qoladi

Birinchi normal shakl (1NF) #

Har bir katakda bitta qiymat bo'lsin. Takrorlanuvchi guruhlar bo'lmasin.

SQL
-- 1NF BUZILGAN: bitta katakda ko'p qiymat
| id | mijoz    | mahsulotlar                        |
|  1 | Husanboy | Klaviatura, Sichqoncha, Monitor    |
SQL
-- 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 |
Vergul bilan ajratilgan ro'yxat - eng ko'p uchraydigan xato
SQL
teglar VARCHAR(255)     -- "python, algoritm, backend"

Bu qulay tuyuladi, lekin:

  • WHERE teglar = 'python' ishlamaydi
  • LIKE '%python%' "python3" ni ham topadi
  • Indeks ishlamaydi
  • Teg nomini o'zgartirish uchun barcha qatorlarni tahrirlash kerak

To'g'ri yechim - alohida jadval:

SQL
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:

SQL
-- 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.

SQL
-- 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).

SQL
-- 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.

SQL
-- 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)
);
Normalizatsiyasiz 1 | Husanboy | +99890 | Klav,Sich 2 | Husanboy | +99890 | Monitor 3 | Husanboy | +99890 | Kabel Ma'lumot takrorlanadi Yangilash xavfli Katakda ko'p qiymat Anomaliyalar 1NF 2NF 3NF mijozlar id, ism, telefon Har bir mijoz BIR MARTA buyurtmalar id, mijoz_id, sana buyurtma_elementlari buyurtma_id mahsulot_id soni, narx Har bir fakt bir joyda
Normalizatsiya bitta katta jadvalni mantiqiy bo'laklarga ajratadi
3NF ni bir jumlada eslab qolish

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.

SQL
-- 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
);
Nima uchun narx takrorlanadi?

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 #

SQL
-- 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 = ?;
DenormalizatsiyaQachon oqlanadi
Tarixiy narxHar doim
Hisoblangan qiymat (COUNT)O'qish yozishdan ancha ko'p bo'lsa
Takrorlangan nomJuda katta hisobotlarda
Yig'ma jadvalAnalitika uchun
Denormalizatsiya - oxirgi chora

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?

Natija
Onlayn do'kon:
- Mijoz
- Mahsulot
- Kategoriya
- Buyurtma
- Yetkazib beruvchi
- Sharh

2-qadam: xususiyatlarni yozish #

Natija
Mahsulot: nomi, tavsif, narx, ombordagi soni, rasm, kategoriya
Buyurtma: mijoz, sana, holat, yetkazish manzili, jami summa

3-qadam: bog'lanishlarni aniqlash #

Natija
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 #

SQL
PRIMARY KEY, FOREIGN KEY, UNIQUE, INDEX

To'liq sxema misoli #

SQL
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 #

Sxemani topshirishdan oldin
SavolTekshirish
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 #

ElementUslubMisol
Jadvalko'plik, kichik harfmahsulotlar
Ustunkichik harf, _yaratilgan_sana
Birlamchi kalitidid
Tashqi kalit<jadval_birlik>_idmijoz_id
Oraliq jadvalikkala nombuyurtma_elementlari
Indeksidx_idx_shahar
Noyob indeksuq_uq_email
Tashqi kalitfk_fk_buyurtma_mijoz
Amaliy topshiriq

Quyidagi yomon jadvalni 3NF ga keltiring:

SQL
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
);
  1. 1NF buzilgan joyni toping va tuzating.
  2. Qanday obyektlar bor? Ularni sanang.
  3. Har biri uchun alohida jadval yarating.
  4. Bog'lanishlarni aniqlang va tashqi kalitlar qo'ying.
  5. Kerakli indekslarni qo'shing.
  6. CREATE TABLE so'rovlarini yozing.
  7. Sxemani qog'ozda chizing.
  8. Sinov ma'lumoti qo'shib, bir nechta JOIN so'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.

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.