Denormalizatsiya — qachon va nima uchun

~15 daq · PostgreSQL · Ma'lumotlar Bazasini Loyihalash

Hisobot sahifasi sekin yuklanyapti. EXPLAIN ANALYZE ko'rsatdi — 8 ta jadval JOIN qilinmoqda, 500 ms ketmoqda. Normalizatsiya to'g'ri — lekin bu holda juda ko'p JOIN. Denormalizatsiya — tezlik uchun ataylab takrorlanish kiritish.


Denormalizatsiya nima?

Normalizatsiya qoidalarini ataylab buzish — ma'lumotni bir necha joyda saqlash. Natijada JOIN kamayadi, so'rovlar tezlashadi. Lekin yangilash murakkablashadi.


Qachon denormalizatsiya?

✅ Denormalizatsiya qilish:
  - O'qish yozishdan ko'p (read-heavy)
  - Hisobot, dashboard, API
  - Ko'p JOIN sekinlashtirgan
  - Cache o'rnini bosib

❌ Denormalizatsiya qilmaslik:
  - Ko'p yangilanuvchi ma'lumot
  - Yozish muhim (write-heavy)
  - Normalizatsiya yetarli tezlikda

Usul 1 — hisoblangan ustun

-- ❌ Normalizatsiya: har so'rovda hisoblash
SELECT f.ism, COUNT(b.id) AS buyurtmalar_soni
FROM foydalanuvchilar f
LEFT JOIN buyurtmalar b ON f.id = b.foydalanuvchi_id
GROUP BY f.id;

-- ✅ Denormalizatsiya: soni to'g'ridan foydalanuvchida
ALTER TABLE foydalanuvchilar ADD COLUMN buyurtmalar_soni INT DEFAULT 0;

-- Buyurtma qo'shilganda
UPDATE foydalanuvchilar SET buyurtmalar_soni = buyurtmalar_soni + 1
WHERE id = :foydalanuvchi_id;

Endi hisobotda JOIN shart emas:

SELECT ism, buyurtmalar_soni FROM foydalanuvchilar ORDER BY buyurtmalar_soni DESC;

Usul 2 — takrorlangan ma'lumot

-- Buyurtmada kategoriya nomini ham saqlash — JOIN kamaytirish
CREATE TABLE buyurtmalar (
  id              SERIAL PRIMARY KEY,
  mahsulot_id     INT REFERENCES mahsulotlar(id),
  mahsulot_nomi   TEXT,   -- ← denormalizatsiya: mahsulotlar jadvalida ham bor
  kategoriya_nomi TEXT,   -- ← denormalizatsiya
  narxi           NUMERIC -- ← denormalizatsiya: o'sha vaqtdagi narx
);

Bu holda mahsulot nomi o'zgarse, eski buyurtmalar eski nomni saqlab qoladi — bu aslida to'g'ri (tarixiy ma'lumot).


Usul 3 — Materialized View

Normalizatsiya saqlab, hisobot uchun denormalizatsiya:

CREATE MATERIALIZED VIEW oylik_hisobot AS
SELECT
  f.ism, f.email,
  COUNT(b.id) AS buyurtmalar,
  SUM(b.summa) AS jami
FROM foydalanuvchilar f
LEFT JOIN buyurtmalar b ON f.id = b.foydalanuvchi_id
GROUP BY f.id;

REFRESH MATERIALIZED VIEW oylik_hisobot; -- kecha yangilanadi

Tez-tez uchraydigan xatolar

Denormalizatsiyadan oldin o'lchash:

-- Avval EXPLAIN ANALYZE bilan sekin ekanligini isbotlang
EXPLAIN ANALYZE SELECT ...;

-- Keyin denormalizatsiya

Ko'pincha to'g'ri index yetarli — denormalizatsiya shart emas.

Sinxronizatsiyani unutish:

-- ❌ buyurtmalar_soni yangilanmagan
INSERT INTO buyurtmalar ...;
-- foydalanuvchilar.buyurtmalar_soni eski qoldi!

Denormalizatsiyada trigger yoki dastur kodi ma'lumotni sinxron ushlab turishi kerak.


Xulosa

Normalizatsiya  → ma'lumot bir joyda, JOIN ko'p
Denormalizatsiya → ma'lumot takrorlanadi, JOIN kam, tezroq

Usullar:
  Hisoblangan ustun     — COUNT, SUM ni jadvalda saqlash
  Takrorlangan ma'lumot — nom, narx kabi ma'lumotni nusxalash
  Materialized View     — hisobot uchun alohida kesh jadval

Qoida: avval o'lchang, keyin denormalizatsiya qiling

Keyingi dars

50-dars: ER Diagram — jadvallar va munosabatlarni loyihalash