WisarWisar
Dasturlash kitobi/6-QISM — Database18 daqiqa

6.10-bob: Indekslar va query optimization, EXPLAIN

6-QISM — Ma'lumotlar bazasi (Database) · 10-mavzu


1. Kirish va motivatsiya

Toza DB dizayni (normalizatsiya) va yaxlitlik (ACID — 6.9)ni bildik. Endi DB'ning eng amaliy, production'da eng muhim mavzusiga — tezlikka — o'tamiz: indekslar (chuqur), query optimization (so'rovni tezlashtirish), va EXPLAIN (so'rov rejasini ko'rish). Bu mavzu — ilovangiz sekin yoki tez ishlashini belgilaydi; va sekin DB — eng ko'p uchraydigan production muammosi.

Tasavvur qiling: loyihangiz yangi — 100 ta foydalanuvchi, hammasi tez. Bir yildan keyin — 1 million foydalanuvchi, va to'satdan ilova sekinlashdi (sahifa 10 sekund yuklanadi). Sabab — deyarli har doim indekssiz so'rovlar: DB har so'rovda butun jadvalni (millionlab qator) birma-bir ko'rib chiqadi. Yechim — indeks: kerakli ma'lumotni darrov topish (kitobning mundarijasi kabi). Indeks bilan — 1 million qatorda ham bir necha millisekund.

6.3 (MongoDB) va 6.6 (PostgreSQL) da indekslarni qisman ko'rdik. Endi chuqur: B-tree qanday ishlaydi, composite/covering/partial indekslar, EXPLAIN ANALYZE (so'rov rejasini o'qish — sekin so'rovni aniqlash), va optimizatsiya amaliyotlari. Bu — backend dasturchini "ishlaydigan kod yozadi"dan "tez, masshtablanadigan tizim quradi"ga ko'taradi (intervyularda ham eng qadrlanadigan bilim).

O'xshatish (indeks): kitobda biror so'zni topish — ikki yo'l. Indekssiz: birinchi sahifadan oxirigacha har sahifani o'qish (1000 sahifa — uzoq). Indeks bilan: kitob oxiridagi alfavit ko'rsatkichka qarash "bu so'z 347-sahifada" to'g'ridan o'sha sahifa (bir necha qadam). DB indeksi — aynan shu alfavit ko'rsatkich: ma'lumotni saralangan holda saqlab, darrov topish imkonini beradi.

Nega muhim?

  • Tezlik = hayot — indekssiz katta DB sekin (eng ko'p production muammosi).
  • Masshtab — million qatorda ham tez ishlash indeksga bog'liq.
  • EXPLAIN — sekin so'rovni topish va tuzatishning yagona yo'li.
  • Ekspertlik — indeks/optimizatsiya — senior backend belgisi.

2. Nazariya — chuqur tushuntirish

2.1. Indekssiz qidiruv muammosi (full scan)

Indekssiz, DB qidiruvni butun jadvalni ko'rib chiqib bajaradi (full table scan / sequential scan):

text
  SELECT * FROM users WHERE email = 'ali@a.uz';

  Indekssiz (Seq Scan):
  1-qator: email = 'ali@a.uz'? yo'q
  2-qator: ? yo'q
  ... (1,000,000 qator birma-bir) ...
   O(n) — qatorlar soniga proporsional (sekin — 3.1: Big-O)

  1 million qatorda — har so'rov millionlab tekshiruv (sekin!)

Bu — kichik jadvalda muammo emas (100 qator — tez). Lekin katta jadvalda (million+) — falokat. Va jadval o'sgan sari sekinlashadi. Indeks — bu muammoni hal qiladi.

2.2. Indeks nima va B-tree (chuqur)

Indeks — ustun(lar) bo'yicha saralangan, alohida tuzilma (asosiy jadvaldan tashqari). Standart turi — B-tree (balanslangan daraxt — 3.6, freecodecamp):

text
  B-tree (balanced tree — 3.6):
                [M]
              /     \
          [F]         [T]
         /   \       /   \
      [A-E] [G-L] [N-S] [U-Z]

  "ali@a.uz" qidirish: M'dan kichik  F  A-E barglari  topildi
   O(log n) — har qadamda yarmini tashlaydi (3.1: Big-O)

  1,000,000 qator: log₂(1M) ≈ 20 qadam (millionlab emas!)

B-tree kuchi: qidiruvni O(n) (full scan) dan O(log n) (daraxt) ga keltiradi. 1 million qator: 1,000,000 tekshiruv o'rniga ~20 qadam. Bu — ming barobar tez. B-tree saralangan — tartiblash (ORDER BY), oraliq (BETWEEN) ham tez.

2.3. Indeks qanday yaratiladi

sql
-- Yagona ustun
CREATE INDEX idx_users_email ON users (email);

-- Noyob (unique — ham indeks, ham cheklov — 6.4: 2.5)
CREATE UNIQUE INDEX idx_users_email ON users (email);

-- Composite (ko'p ustun — 2.5)
CREATE INDEX idx_orders_user_date ON orders (user_id, created_at);

-- Indeksni o'chirish
DROP INDEX idx_users_email;

Primary Key avtomatik indekslangan 6.4-bob. Unique constraint ham indeks yaratadi. Foreign Key — avtomatik indekslanmaydi (ko'p DB'da) — JOIN tezligi uchun qo'lda qo'shish kerak 2.10-bob.

2.4. Qaysi ustunga indeks (va qaysiga emas)

text
   Indeks kerak:
  - WHERE'da tez-tez ishlatiladigan (email, status, user_id)
  - JOIN ustunlari (FK — 2.10)
  - ORDER BY ustunlari
  - UNIQUE bo'lishi kerak (email)

   Indeks kerak emas / zarari:
  - Kichik jadval (full scan baribir tez)
  - Kam ishlatiladigan ustun
  - Tez-tez o'zgaradigan, kam qidiriladigan (yozish sekinlashadi)
  - Past kardinallik (faqat 2-3 qiymat — masalan boolean — kam foyda)

Kardinallik — ustundagi noyob qiymatlar soni. Yuqori (email — har xil) indeks foydali. Past (jins: erkak/ayol — 2 qiymat) indeks kam foyda (yarmini baribir o'qiydi). Indeks — yuqori kardinallikli, tez-qidiriladigan ustunga.

2.5. Composite (birikma) indeks va ustun tartibi

Composite indeks — bir necha ustun bo'yicha. Ustun tartibi — eng muhim qaror (ai2sql):

sql
CREATE INDEX idx ON orders (user_id, created_at, status);
text
  (a, b, c) indeksi QO'LLAB-QUVVATLAYDI:
   WHERE a            (faqat birinchi)
   WHERE a AND b      (chapdan ketma-ket)
   WHERE a AND b AND c
   WHERE b            (birinchini o'tkazib — ishlamaydi!)
   WHERE c
   WHERE b AND c

   "leftmost prefix" qoidasi: chapdan boshlab ketma-ket ustunlar

Composite indeks — chapdan (leftmost prefix): (a, b, c) indeksi a, a+b, a+b+c so'rovlariga ishlaydi, lekin b yoki c yolg'iz uchun ishlamaydi. Shuning uchun tartib muhim: eng ko'p filtrlanadiganni birinchi. ESR qoidasi (6.3: 2.9): Equality Sort Range.

2.6. Covering index (qoplovchi indeks)

Covering index — so'rov kerakli barcha ustunlarni o'z ichiga oladi DB jadvalga umuman murojaat qilmaydi (faqat indeksdan — ai2sql):

sql
-- So'rov: SELECT ism, email FROM users WHERE status = 'faol';
CREATE INDEX idx_cover ON users (status) INCLUDE (ism, email);   -- PostgreSQL 11+
-- status bo'yicha topadi + ism/email indeksda  jadval O'QILMAYDI (juda tez)

Covering index — eng tez: DB indeksdan hamma narsani oladi (jadvalga "key lookup" — qimmat qadam — kerak emas). INCLUDE (PostgreSQL) — qo'shimcha ustunlarni indeksda saqlaydi (qidiruvga emas, qaytarishga). Tez-tez ishlatiladigan, muhim so'rovlar uchun.

2.7. Partial index (qisman indeks)

Partial index — faqat ma'lum qatorlarga indeks (shart bilan):

sql
-- Faqat faol foydalanuvchilar (o'chirilmaganlar) indekslanadi
CREATE INDEX idx_faol ON users (email) WHERE deleted_at IS NULL;

-- Faqat tugallanmagan buyurtmalar (tez-qidiriladigan kichik qism)
CREATE INDEX idx_kutilmoqda ON orders (created_at) WHERE status = 'kutilmoqda';

Partial index — kichikroq (faqat kerakli qatorlar), tezroq, kam joy. Misol: 1 million buyurtmaning faqat 1000 tasi "kutilmoqda" — faqat shularga indeks (admin panel uchun). PostgreSQL'da kuchli (MySQL'da yo'q).

2.8. Boshqa indeks turlari (qisqacha)

text
  B-tree   — default (tenglik, oraliq, tartib — 2.2)
  Hash     — faqat tenglik (=) — kamdan-kam (B-tree odatda yetadi)
  GIN      — JSONB, massiv, to'liq matn (6.6: 2.11)
  GiST     — geometrik, range
  BRIN     — juda katta, tartiblangan (vaqt seriyasi — kam joy)

Ko'p holatda B-tree (default). GIN — JSONB/massiv/matn 6.6-bob. Boshqalar — maxsus holatlar. Indeks turini ma'lumot va so'rovga qarab tanlang.

2.9. EXPLAIN — so'rov rejasini ko'rish (eng muhim vosita)

EXPLAIN — DB so'rovni qanday bajarishini ko'rsatadi (reja — oneuptime):

sql
EXPLAIN SELECT * FROM users WHERE email = 'ali@a.uz';
-- Reja: Seq Scan (yomon — full scan!) yoki Index Scan (yaxshi)

EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'ali@a.uz';
-- ANALYZE — so'rovni HAQIQATAN bajaradi + ASL vaqtni ko'rsatadi
text
  Reja turlari (PostgreSQL):
  Seq Scan      — butun jadval (indekssiz — YOMON katta jadvalda — 2.1)
  Index Scan    — indeksdan topish (YAXSHI — 2.2)
  Index Only Scan — faqat indeksdan (covering — eng tez — 2.6)
  Bitmap Scan   — ko'p qator (oraliq)
  Nested Loop / Hash Join — JOIN usullari

EXPLAIN ANALYZE — optimizatsiyaning kaliti (oneuptime): indeks qo'shishdan oldin va keyin EXPLAIN ANALYZE bilan tekshiring. Seq Scan katta jadvalda — yomon belgi (indeks kerak). Index Scan — yaxshi. "Reja"ni o'qish — sekin so'rovni topish va tuzatishning yagona ishonchli yo'li.

2.10. EXPLAIN'ni o'qish (nimaga e'tibor)

text
  EXPLAIN ANALYZE natijasida:
  - Seq Scan vs Index Scan (indeks ishlatilyaptimi)
  - "Filter" — indeksdan keyin qo'shimcha filtr (ko'p qator o'qildi — yomon)
  - "Index Cond" — indeks shartlari (yaxshi — filtr indeksda)
  - actual time — haqiqiy vaqt (ms)
  - rows — qancha qator qaytdi/o'qildi
  - cost — DB baholagan "narx"

Asosiy qoida (ai2sql): "Filter" ko'rsangiz — kerakidan ko'p qator o'qilmoqda (indeks yetmaydi). Ideal: filtrlash "Index Cond" ichida (indeksda). actual time katta yoki rows kutilganidan ko'p — muammo belgisi.

2.11. N+1 muammosi (eng ko'p uchraydigan)

N+1 query — eng keng tarqalgan performance muammosi (6.7: 1-holat, ORM'da ham — 6.14):

text
   N+1 (1 + N so'rov):
  const users = await q("SELECT * FROM users");        // 1 so'rov
  for (const u of users)                                // N foydalanuvchi
    u.orders = await q("SELECT * FROM orders WHERE user_id = $1", [u.id]);   // N so'rov!
   1 + 100 = 101 so'rov (sekin!)

   Bitta JOIN yoki IN:
  await q("SELECT u.*, o.* FROM users u LEFT JOIN orders o ON u.id = o.user_id");   // 1 so'rov
  yoki: WHERE user_id IN (...)                          // 2 so'rov

N+1 — ayniqsa ORM'da (6.14 — populate/include) yashirin. 100 element 101 so'rov sekin. Yechim: JOIN 6.7-bob, IN, yoki ORM'ning eager loading (include/populate). EXPLAIN bilan ko'rinmaydi (ko'p alohida so'rov) — kodni tekshirish kerak.

2.12. Query optimization amaliyotlari

text
   Kerakli ustunlarni tanlang (SELECT * emas — kam ma'lumot, covering imkoni — 6.4)
   WHERE'ni indekslangan ustunga (Seq Scan'dan saqlanish — 2.9)
   Funksiyani indekslangan ustunga qo'llamang (WHERE LOWER(email) — indeks ishlamaydi!)
   LIMIT bilan cheklash (katta natija — 6.4)
   JOIN o'rniga subquery yoki teskari (o'lchab)
   Sahifalashda OFFSET o'rniga keyset (katta sahifa — 2.13)
   EXPLAIN ANALYZE bilan o'lchang (taxmin qilmang — 2.9)

Funksiya indeksni buzadi: WHERE LOWER(email) = 'ali@a.uz'email indeksini ishlatmaydi (funksiya qo'llangan). Yechim: functional index (CREATE INDEX ON users (LOWER(email))) yoki ma'lumotni normallashtirib saqlash (kichik harf). Bu — yashirin sekinlik sababi.

2.13. Keyset pagination (katta sahifalash)

sql
--  OFFSET — katta sahifada sekin (DB barcha oldingilarni o'qiydi)
SELECT * FROM posts ORDER BY id DESC LIMIT 20 OFFSET 100000;   -- 100020 qator o'qiydi!

--  Keyset (cursor) — oxirgi ko'rilgandan keyin (tez)
SELECT * FROM posts WHERE id < $1 ORDER BY id DESC LIMIT 20;   -- $1 = oxirgi id

OFFSET muammosi: OFFSET 100000 — DB 100000 qatorni o'qib tashlaydi (sekin). Keyset pagination — "oxirgi ko'rilgan id'dan keyin" (indeks bilan to'g'ridan) — katta sahifada ham tez. Cheksiz scroll (feed) uchun ideal.

2.14. Indeks narxi (yana — balans)

text
  Har indeks:
   O'qishni tezlashtiradi (qidiruv — 2.2)
   Yozishni sekinlashtiradi (INSERT/UPDATE/DELETE'da indeks ham yangilanadi)
   Joy oladi (disk/RAM)

   Kerakli indekslar (tez-qidiriladigan); ortiqcha emas
   Yozish ko'p jadvalda — ehtiyot (har indeks yozishni sekinlatadi)

Balans: indeks — o'qish uchun yaxshi, yozish uchun yuk. O'qish ko'p (mahsulot katalogi) ko'proq indeks. Yozish ko'p (log) kam indeks. Ishlatilmaydigan indekslarni o'chiring (joy + yozish tejaydi — pg_stat_user_indexes bilan topish).

2.15. Boshqa optimizatsiya (qisqacha)

text
  Connection pool (6.5, 6.6) — ulanish qayta ishlatish
  Kesh (Redis — 5.21) — tez-o'qiladigan natija
  Materialized view 6.8-bob — og'ir hisobot keshlash
  Denormalizatsiya (6.9: 2.7) — JOIN kamaytirish
  VACUUM/ANALYZE (PostgreSQL) — statistikani yangilash (optimizator uchun)
  Read replica — o'qishni alohida serverga (masshtab — 9)

2.16. Best practices (14)

text
   WHERE/JOIN/ORDER BY ustunlariga indeks (2.4, 2.10)
   Composite indeks — to'g'ri tartib (leftmost, ESR — 2.5)
   EXPLAIN ANALYZE bilan o'lchang (taxmin qilmang — 2.9)
   Seq Scan (katta jadval) — indeks qo'shing; Filter  Index Cond 2.10-bob
   N+1 dan saqlaning (JOIN/IN/eager — 2.11)
   Funksiya indeksni buzadi (functional index — 2.12)
   Katta sahifalash — keyset (OFFSET emas — 2.13)
   Ortiqcha indeks emas (yozish narxi — 2.14)
   SELECT kerakli ustunlar; kesh 5.21-bob tez-o'qiladiganga

3. Sintaksis — tez ma'lumotnoma

sql
-- Indeks (2.3, 2.5-2.7)
CREATE INDEX idx ON jadval (ustun);                          -- B-tree
CREATE INDEX idx ON orders (user_id, created_at);            -- composite (leftmost — 2.5)
CREATE INDEX idx ON users (status) INCLUDE (ism, email);     -- covering (2.6)
CREATE INDEX idx ON users (email) WHERE deleted_at IS NULL;  -- partial (2.7)
CREATE INDEX idx ON users (LOWER(email));                    -- functional (2.12)

-- EXPLAIN (2.9)
EXPLAIN ANALYZE SELECT ...;   -- reja + haqiqiy vaqt

-- Keyset pagination (2.13)
WHERE id < $1 ORDER BY id DESC LIMIT 20;   -- OFFSET o'rniga

4. Batafsil misollar

Misol 1 — Indeks ta'siri (EXPLAIN bilan — 2.9)

sql
-- Indekssiz (Seq Scan — 2.1)
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'ali@a.uz';
-- Seq Scan on users (cost=0..18000 rows=1) actual time=45ms   SEKIN (full scan)

-- Indeks qo'shish
CREATE INDEX idx_users_email ON users (email);

-- Endi (Index Scan — 2.2)
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'ali@a.uz';
-- Index Scan using idx_users_email (cost=0..8 rows=1) actual time=0.05ms   TEZ (900x!)

Misol 2 — Composite indeks (to'g'ri tartib — 2.5)

sql
-- So'rov: foydalanuvchining sana bo'yicha buyurtmalari
-- SELECT * FROM orders WHERE user_id = 5 ORDER BY created_at DESC;

--  To'g'ri composite (user_id — equality, created_at — sort; ESR — 2.5)
CREATE INDEX idx_orders ON orders (user_id, created_at DESC);
-- WHERE user_id + ORDER BY created_at — ikkalasi indeksdan (tez)

--  Noto'g'ri tartib (created_at, user_id) — WHERE user_id ishlatmaydi (2.5)

Misol 3 — Covering index (2.6)

sql
-- Tez-tez: SELECT ism, email FROM users WHERE status = 'faol';
CREATE INDEX idx_cover ON users (status) INCLUDE (ism, email);

EXPLAIN ANALYZE SELECT ism, email FROM users WHERE status = 'faol';
-- Index Only Scan (jadval O'QILMAYDI — eng tez — 2.6)

Misol 4 — Partial index (2.7)

sql
-- Admin panel: faqat kutilayotgan buyurtmalar (kichik qism)
CREATE INDEX idx_kutilmoqda ON orders (created_at)
WHERE status = 'kutilmoqda';                              -- faqat shular indekslanadi

-- Bu so'rov partial indeksdan foydalanadi (tez, kichik indeks — 2.7)
SELECT * FROM orders WHERE status = 'kutilmoqda' ORDER BY created_at;

Misol 5 — N+1 ni JOIN bilan tuzatish (2.11)

js
//  N+1 (101 so'rov — 2.11)
const users = await pool.query("SELECT * FROM users LIMIT 100");
for (const u of users.rows) {
  const o = await pool.query("SELECT * FROM orders WHERE user_id = $1", [u.id]);   // har biriga!
  u.orders = o.rows;
}

//  Bitta JOIN (1 so'rov — 6.7)
const { rows } = await pool.query(`
  SELECT u.id, u.ism, json_agg(o.*) AS orders
  FROM users u
  LEFT JOIN orders o ON u.id = o.user_id
  GROUP BY u.id
  LIMIT 100
`);
// json_agg — har user'ning buyurtmalarini massivga yig'adi (PostgreSQL)

Misol 6 — Funksiya indeksni buzishi va functional index (2.12)

sql
--  email indeksi BOR, lekin LOWER() uni ishlatmaydi (2.12)
CREATE INDEX idx_email ON users (email);
EXPLAIN ANALYZE SELECT * FROM users WHERE LOWER(email) = 'ali@a.uz';
-- Seq Scan (indeks ishlatilmadi — funksiya!)

--  Functional index (LOWER bo'yicha)
CREATE INDEX idx_email_lower ON users (LOWER(email));
EXPLAIN ANALYZE SELECT * FROM users WHERE LOWER(email) = 'ali@a.uz';
-- Index Scan (functional indeks ishladi — 2.12)

Misol 7 — Keyset pagination (2.13)

js
//  OFFSET (katta sahifada sekin — 2.13)
export const eskiUsul = (page) => pool.query(
  "SELECT * FROM posts ORDER BY id DESC LIMIT 20 OFFSET $1", [(page - 1) * 20]
);

//  Keyset (cursor — tez, cheksiz scroll — 2.13)
export const keyset = (oxirgiId) => pool.query(
  oxirgiId
    ? "SELECT * FROM posts WHERE id < $1 ORDER BY id DESC LIMIT 20"   // keyingi sahifa
    : "SELECT * FROM posts ORDER BY id DESC LIMIT 20",                // birinchi
  oxirgiId ? [oxirgiId] : []
);
// Frontend oxirgi ko'rilgan id'ni saqlaydi, keyingi so'rovda yuboradi

Misol 8 — Indekslarni tahlil qilish (PostgreSQL — 2.14)

sql
-- Ishlatilmaydigan indekslarni topish (joy/yozish tejash — 2.14)
SELECT indexrelname, idx_scan
FROM pg_stat_user_indexes
WHERE idx_scan = 0;                                       -- hech ishlatilmagan  o'chirish mumkin

-- Sekin so'rovlarni topish (pg_stat_statements kengaytmasi)
SELECT query, mean_exec_time, calls
FROM pg_stat_statements
ORDER BY mean_exec_time DESC LIMIT 10;                    -- eng sekin 10 so'rov

-- Statistikani yangilash (optimizator uchun — 2.15)
ANALYZE users;

5. To'g'ri va noto'g'ri holatlar

1) Tez-qidiriladigan ustunga indekssiz

text
 email/user_id indekssiz  Seq Scan (sekin — 2.1)
 CREATE INDEX (Index Scan — 2.3)

2) Composite indeks noto'g'ri tartib

sql
--  (created_at, user_id) — WHERE user_id ishlatmaydi (2.5)
--  (user_id, created_at) — leftmost (2.5)

3) Funksiya indekslangan ustunda

sql
--  indeks ishlamaydi (2.12)
WHERE LOWER(email) = '...'   -- email indeksi bekor

--  functional index yoki normallashtirilgan ma'lumot

4) N+1 so'rov

text
 tsiklda alohida so'rov (101 so'rov — 2.11)
 JOIN/IN (1-2 so'rov)

5) Katta OFFSET pagination

sql
--  OFFSET 100000 (sekin — 2.13)
--  keyset (WHERE id < oxirgi)

6) Hamma ustunga indeks

text
 har ustunga indeks (yozish sekin, joy — 2.14)
 faqat tez-qidiriladigan (EXPLAIN bilan tasdiqlangan)

6. Keng tarqalgan xatolar va yechimlari

Xato 1 — So'rov sekin (production)

Sababi: indekssiz Seq Scan 2.1-bob. Yechimi: EXPLAIN ANALYZE; WHERE ustuniga indeks 2.3-bob.

Xato 2 — Indeks qo'shdim, lekin ishlamayapti

Sababi: funksiya (LOWER — 2.12), noto'g'ri composite tartib 2.5-bob, yoki kichik jadval (optimizator Seq tanlaydi). Yechimi: EXPLAIN bilan tekshiring; functional index; tartibni to'g'irlang.

Xato 3 — Ilova o'sgan sari sekinlashdi

Sababi: jadval o'sdi, indekssiz so'rovlar 2.1-bob. Yechimi: sekin so'rovlarni topish (pg_stat_statements — Misol 8); indeks.

Xato 4 — INSERT/UPDATE sekinlashdi

Sababi: ortiqcha indekslar (har yozishda yangilanadi — 2.14). Yechimi: ishlatilmaydigan indekslarni o'chiring (Misol 8).

Xato 5 — N+1 (ORM'da yashirin)

Sababi: lazy loading (har element — so'rov — 2.11). Yechimi: eager loading (include/populate); JOIN.

Xato 6 — Sahifa raqami oshgani sayin sekin

Sababi: OFFSET 2.13-bob. Yechimi: keyset pagination (Misol 7).


7. Integratsiya — bu mavzu stack'ning qayerida uchraydi

  • Tree/Big-O (3.6, 3.1): B-tree, O(log n).
  • MongoDB indeks 6.3-bob: bir xil tamoyil (B-tree, ESR).
  • PostgreSQL 6.6-bob: GIN, partial, EXPLAIN.
  • JOIN 6.7-bob: N+1, JOIN indeks.
  • Normalizatsiya 6.9-bob: denormalizatsiya — optimizatsiya.
  • Redis 5.21-bob: kesh — DB yukini kamaytirish.
  • Materialized view 6.8-bob: og'ir hisobot keshlash.
  • ORM 6.14-bob: N+1, eager loading.
  • Monitoring 10.9-bob: sekin so'rov kuzatuvi.

8. Eng yaxshi amaliyotlar (best practices)

  • WHERE/JOIN/ORDER BY ustunlariga indeks 2.4-bob; FK'ga ham 2.10-bob.
  • Composite — to'g'ri tartib (leftmost, ESR — 2.5).
  • Covering index (tez-tez, muhim so'rov — 2.6); partial (kichik qism — 2.7).
  • EXPLAIN ANALYZE bilan o'lchang (taxmin qilmang — 2.9, 2.10).
  • N+1 dan saqlaning (JOIN/IN/eager — 2.11).
  • Funksiya indeksni buzadi (functional index — 2.12).
  • Katta sahifalash — keyset (OFFSET emas — 2.13).
  • Ortiqcha indeks emas (yozish narxi; ishlatilmaganni o'chiring — 2.14).
  • SELECT kerakli ustunlar (covering imkoni — 2.12).
  • Kesh/materialized view (og'ir/tez-o'qiladigan — 2.15, 5.21).

9. Amaliy loyiha: "DB Performance Optimizatsiya"

DB tezligini professional darajada mustahkamlash.

Maqsad

EXPLAIN bilan sekin so'rovlarni topib, indekslar va optimizatsiya bilan tezlashtirish (katta ma'lumotli e-commerce).

Talablar (requirements)

  1. Katta ma'lumot: ko'p qator (seed — 100K+) generatsiya qiling (test uchun).
  2. EXPLAIN tahlil: sekin so'rovlarni EXPLAIN ANALYZE bilan aniqlang (Seq Scan — Misol 1, 2.9).
  3. Indekslar: WHERE/JOIN/ORDER ustunlariga; oldin/keyin EXPLAIN solishtiring (Misol 1, 2.3).
  4. Composite: to'g'ri tartib (leftmost test — Misol 2, 2.5).
  5. Covering: tez-tez so'rovga INCLUDE (Misol 3, 2.6).
  6. Partial: kichik qism (kutilayotgan buyurtma — Misol 4, 2.7).
  7. N+1 tuzatish: tsikldagi so'rovni JOIN'ga (Misol 5, 2.11).
  8. Functional index: LOWER(email) (Misol 6, 2.12).
  9. Keyset pagination: OFFSET o'rniga (Misol 7, 2.13).
  10. Indeks audit: ishlatilmaydiganlarni toping (Misol 8, 2.14).

Maslahatlar (hint)

  • EXPLAIN ANALYZE — oldin/keyin solishtiring (2.9, taxmin qilmang).
  • Seq Scan (katta jadval) indeks (2.1, 1-xato).
  • Composite: equality sort (ESR — 2.5).
  • Funksiya functional index (2.12, 3-holat).
  • N+1 JOIN/json_agg (Misol 5).
  • OFFSET keyset (Misol 7).
  • Ortiqcha indeks pg_stat (Misol 8).

"Tayyor" mezonlari (acceptance criteria)

  • Katta ma'lumot bilan test.
  • EXPLAIN ANALYZE bilan sekin so'rov topilgan.
  • Indeks oldin/keyin tezlik farqi ko'rsatilgan.
  • Composite to'g'ri tartib (leftmost).
  • Covering index (Index Only Scan).
  • Partial index.
  • N+1 JOIN bilan tuzatilgan.
  • Functional index (LOWER).
  • Keyset pagination.
  • Ortiqcha indeks tahlili.

Yechim kodi ataylab berilmagan — bu loyihani o'zingiz yozib ko'ring.


10. Xulosa va keyingi bobga ko'prik

Bu bobda DB tezligi va optimizatsiyasini chuqur o'rgandik:

  • Indekssiz — full scan (O(n), sekin — 2.1); indeks — B-tree (O(log n), tez — 2.2).
  • Indeks turlari: yagona, composite (leftmost/ESR — 2.5), covering (INCLUDE — 2.6), partial (shart — 2.7), GIN/functional (2.8, 2.12).
  • EXPLAIN ANALYZE (so'rov rejasi — Seq vs Index Scan, Filter vs Index Cond — 2.9, 2.10) — optimizatsiyaning kaliti.
  • N+1 (JOIN/IN — 2.11); keyset pagination (OFFSET emas — 2.13); indeks narxi/balans 2.14-bob; kesh/materialized 2.15-bob.

Keyingi bob — 6.11-bob: ORM — Sequelize (model, relations, migration). Xom SQL (6.4-6.10) ni chuqur bildik; endi ORM (Object-Relational Mapping) ga o'tamiz — SQL'ni JS obyektlari bilan ishlash. Birinchi ORM — Sequelize: model, bog'lanishlar (relations), migration. ORM — produktivlikni oshiradi, lekin SQL bilimini talab qiladi (shuning uchun avval SQL'ni o'rgandik).


Foydalanilgan rasmiy/ishonchli manbalar

  • OneUptime — PostgreSQL query optimization 2026 (EXPLAIN ANALYZE); Mydbops — indexing best practices
  • AI2SQL — SQL indexing best practices (composite, covering); freeCodeCamp — how indexes work (B-tree)
  • PostgreSQL docs — Indexes, EXPLAIN, pg_stat_statements

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
6.10-bob: Indekslar va query optimization, EXPLAIN — Wisar