IlmHamroh
JavaScript Full-stack/27-qism. Ma'lumotlar bazasi chuqur: Postgres, ORM, Mongo, Redis49/65-dars17 daqiqa
Mundarija (29)

MongoDB indekslari: COLLSCAN va IXSCAN, ESR qoidasi, multikey, text, TTL va partial

Qisqacha: Indekssiz MongoDB butun kolleksiyani skanerlaydi (COLLSCAN): kanonda 500 000 hujjatdan 20 tasini topish 353 ms oldi. To'g'ri compound indeks bilan (IXSCAN) — 20 ta kalit, 20 ta hujjat, 1–5 ms. Maydonlar tartibi ESR qoidasi bo'yicha: avval Equality (tenglik), keyin Sort, oxirida Range (diapazon). Massiv maydondagi indeks — multikey, matn uchun — text (o'zbekcha stemming yo'q, sukut OR), muddatli hujjatlar uchun — TTL. Har indeks yozishni sekinlashtiradi: 20 000 hujjat 398 ms dan 921 ms ga.

Bu darsda

  • explain("executionStats") ni o'qib, COLLSCAN va IXSCAN'ni farqlaysiz.
  • Compound indeksni ESR qoidasi bo'yicha tuzasiz va noto'g'ri tartibning narxini ko'rasiz.
  • Multikey, text, unique, partial va TTL indekslarni ishlatasiz va ularning tuzoqlarini bilasiz.
  • Indeks yozishga qancha qimmat tushishini o'lchov bilan baholaysiz.

Oldin bilishingiz kerak: Aggregation pipeline, Indeks nima: B-tree ichidan, Qaysi ustunga va qanday tartibda indeks, EXPLAIN ANALYZE'ni o'qish.

1. Nega bu kerak?

26-qismda Postgres indekslarini chuqur o'rgandik: B-tree, tarkibiy indeks va chap prefiks, partial va covering, EXPLAIN (Indeks nima, Qaysi ustunga va qanday tartibda indeks). Yaxshi xabar: MongoDB indekslari ham B-tree, va asosiy g'oyalar o'sha. Bu darsda faqat Mongo'ga xos narsalarni ko'ramiz: ESR qoidasi, massivlar, matn, TTL.

Savol oddiy. Ilovada "Azizning bajarilmagan, 2025 dan keyingi oxirgi 20 vazifasi" so'rovi. Kolleksiyada yarim million vazifa. Indekssiz Mongo har birini ochib ko'radi.

O'xshatish: kutubxonada katalog bo'lmasa, kerakli kitobni topish uchun har javonni ko'zdan kechirasiz. Katalog muallif bo'yicha tartiblangan bo'lsa — darhol to'g'ri javonga borasiz. Lekin katalogni har yangi kitob kelganda yangilash kerak — bu indeksning narxi.

Hamma o'lchovlar — kanon o'lchovi (IlmHamroh, 2026-10): Aggregation pipeline darsida Postgres'dan ko'chirilgan katta.vazifalar — 500 000 hujjat, _id va egasi — sonlar. MongoDB 8.3.13 (Docker, WSL2), Node 24.21.0, mongodb 7.7.0, i5-12500H. Millisekundlar — bitta o'lchov, band mashinada.

2. explain: so'rov qanday bajarildi

2.1 Indekssiz

Kanon so'rovi — egasi 77, bajarilmagan, 2025-yildan keyin yaratilgan, eng yangi 20 tasi:

js
const sorov = () => K.find({
  egasi: 77,
  bajarildi: false,
  yaratilgan: { $gte: new Date("2025-01-01") },
}).sort({ yaratilgan: -1 }).limit(20);

const e = await sorov().explain("executionStats");

K — katta.vazifalar kolleksiyasi. explain("executionStats") — so'rovni haqiqatan bajarib, reja va statistikani qaytaradi (Postgres'dagi EXPLAIN ANALYZE). Kanon undan asosiy raqamlarni ajratib chiqardi:

text
{"indekssiz":{"reja":"SORT ← COLLSCAN","natija":20,"kalitlar":0,"hujjatlar":500000,"ms":353}}
Maydon (explain'da) Kanon nomi Ma'nosi
winningPlan bosqichlari reja pastdan yuqoriga: COLLSCAN → SORT
nReturned natija qaytgan hujjatlar
totalKeysExamined kalitlar indeksda ko'rilgan kalitlar
totalDocsExamined hujjatlar ochib ko'rilgan hujjatlar
executionTimeMillis ms server ichidagi vaqt

O'qiymiz: COLLSCAN — butun kolleksiya skani: 500 000 hujjat ochildi, 20 tasi qaytdi. Keyin SORT — xotirada saralash. 353 ms.

Asosiy ko'rsatkich — hujjatlar / natija nisbati. Ideal holatda 1: nechta hujjat kerak bo'lsa, shuncha o'qildi. Bu yerda 25 000.

2.2 Bosqich nomlari

Bosqich Ma'nosi Postgres o'xshashi
COLLSCAN butun kolleksiya Seq Scan
IXSCAN indeks bo'ylab Index Scan (faqat indeks qismi)
FETCH indeksdan topilgan hujjatni o'qish heap'dan qator olish
SORT xotirada saralash Sort
LIMIT kesish Limit

3. Compound indeks va ESR qoidasi

3.1 Noto'g'ri tartib: E–R–S

Compound indeks — bir nechta maydonli indeks; bu Postgres'dagi tarkibiy indeksning (Qaysi ustunga va qanday tartibda indeks) Mongo'dagi nomi. Chap prefiks qoidasi bu yerda ham amal qiladi.

Birinchi urinish — so'rovdagi maydonlar "mantiqiy" tartibda: egasi, yaratilgan, bajarildi:

js
await K.createIndex(
  { egasi: 1, yaratilgan: 1, bajarildi: 1 },
  { name: "noto'g'ri_ERS" },
);
await sorov().hint("noto'g'ri_ERS").explain("executionStats");

hint — planner'ga "aynan shu indeksni ishlat" deb majburlash (taqqoslash uchun).

text
{"E_R_S tartib":{"reja":"LIMIT ← FETCH ← IXSCAN(noto'g'ri_ERS)","natija":20,"kalitlar":43,"hujjatlar":20,"ms":4}}

353 ms dan 4 ms ga — katta yutuq. Lekin kalitlar: 43 — kerakli 20 ta uchun 43 ta kalit ko'rildi. Nega? Indeksda egasi dan keyin yaratilgan turadi, bajarildi esa oxirida. Indeks egasi 77 ning hamma 2025+ vazifalarini vaqt tartibida beradi — bajarilganlari ham aralash. Ularni bittalab ko'rib, bajarildi: true larini tashlash kerak bo'ldi.

3.2 ESR: Equality, Sort, Range

js
await K.createIndex(
  { egasi: 1, bajarildi: 1, yaratilgan: -1 },
  { name: "ESR" },
);
await sorov().hint("ESR").explain("executionStats");
await sorov().explain("executionStats");   // planner o'zi tanlasin
text
{"ESR":{"reja":"LIMIT ← FETCH ← IXSCAN(ESR)","natija":20,"kalitlar":20,"hujjatlar":20,"ms":5}}
{"planner o'zi tanladi":{"reja":"LIMIT ← FETCH ← IXSCAN(ESR)","natija":20,"kalitlar":20,"hujjatlar":20,"ms":1}}

kalitlar: 20, hujjatlar: 20, natija: 20 — ideal. Va hint siz planner ikki indeks orasidan o'zi ESR ni tanladi. (Millisekundlar 1–5 — bu o'lchamda shovqin; asosiy dalil — kalitlar soni.)

ESR qoidasi (MongoDB hujjatidagi tavsiya) — compound indeksda maydonlar tartibi:

  1. E — Equality (tenglik): aniq qiymat bilan solishtiriladigan maydonlar (egasi: 77, bajarildi: false).
  2. S — Sort (saralash): sort dagi maydonlar.
  3. R — Range (diapazon): $gte, $lt, $in kabi.

Bizda saralash va diapazon bitta maydon (yaratilgan) — u tenglik maydonlaridan keyin turadi. Indeks ichida egasi 77 + bajarilmagan qism allaqachon vaqt bo'yicha tartiblangan: Mongo boshidan 20 tasini oladi va to'xtaydi. SORT bosqichi yo'q.

flowchart LR
  E["E: egasi = 77, bajarildi = false"] --> S["S: yaratilgan bo'yicha tartiblangan"]
  S --> R["R: yaratilgan >= 2025"]
  R --> L["LIMIT 20: birinchi 20 kalit"]

Diagrammaga qarang: indeks ichida avval tenglik bilan torayamiz, keyin tayyor tartibdan diapazon chegarasigacha o'qiymiz. Postgres'dagi "tenglik ustunlari oldinda, diapazon — oxirida" qoidasining o'zi (Qaysi ustunga va qanday tartibda indeks), faqat Mongo saralashni alohida harf bilan ajratadi.

3.3 Range saralashdan oldin bo'lsa

Uchinchi holat: diapazon bitta maydonda, saralash — boshqasida:

js
await K.find({
  egasi: 77,
  yaratilgan: { $gte: new Date("2025-01-01") },
}).sort({ ustuvorlik: 1 }).limit(20)
  .hint("noto'g'ri_ERS").explain("executionStats");
text
{"SORT xotirada":{"reja":"SORT ← FETCH ← IXSCAN(noto'g'ri_ERS)","natija":20,"kalitlar":344,"hujjatlar":344,"ms":5}}

Indeks { egasi, yaratilgan, … } diapazonni topadi (344 ta mos), lekin ular ustuvorlik bo'yicha tartiblanmagan. Mongo hammasini olib, xotirada saraladi va keyin 20 tasini qaytardi. 344 — kichik son; lekin egasining 100 000 vazifasi bo'lsa — 100 000 hujjat xotiraga, va xotira chegarasidan oshsa — xato yoki diskka yozish. To'g'ri indeks: { egasi: 1, ustuvorlik: 1, yaratilgan: 1 } — E, S, R.

Tekshirib ko'ring: So'rov: find({ holat: "yangi", narx: { $lt: 50000 } }).sort({ sana: -1 }). ESR bo'yicha indeks qanday bo'ladi?

Javob

{ holat: 1, sana: -1, narx: 1 }. Tenglik (holat) — birinchi, saralash (sana) — ikkinchi, diapazon (narx) — oxirida. { holat, narx, sana } bo'lsa, narx diapazoni sanalarni "aralashtiradi" va xotirada saralash kerak bo'ladi — kanondagi 344 kalitli holat.

4. Multikey: massivga indeks

teglar — massiv. Massiv maydondagi indeks — multikey: har element alohida kalit bo'ladi. 3 tegli vazifa indeksda 3 marta uchraydi.

js
await K.find({ teglar: "sport" }).limit(5)
  .explain("executionStats");                  // indekssiz
await K.createIndex({ teglar: 1 }, { name: "teglar" });
await K.find({ teglar: "sport", egasi: 77 })
  .explain("executionStats");
text
{"teg indekssiz":{"reja":"LIMIT ← COLLSCAN","natija":5,"kalitlar":0,"hujjatlar":58,"ms":0}}
{"teg multikey":{"reja":"FETCH ← IXSCAN(noto'g'ri_ERS)","natija":42,"kalitlar":401,"hujjatlar":401,"ms":12}}

Ikki qiziq kuzatuv:

  1. Indekssiz, lekin 58 hujjat. limit(5) bor: Mongo skanerni boshladi va 58-hujjatda 5 ta sport ni topib to'xtadi. Tez-tez uchraydigan qiymat + kichik limit — COLLSCAN ham tez. Lekin bu omad: kam uchraydigan teg uchun butun kolleksiya o'qiladi.
  2. teglar indeksi bor, planner esa noto'g'ri_ERS ni tanladi. { teglar: "sport", egasi: 77 } — ikkala shartga bitta indeks yo'q. Planner variantlarni sinab ko'rib (egasi bo'yicha 401 hujjat, teg bo'yicha esa ko'p), egasi indeksini yutuqli deb topdi. Planner tanlovi ma'lumotga bog'liq — buni explain dan bilasiz, taxmindan emas.

Indekslar hajmi (kanon collStats dan):

text
indekslar: ESR, noto'g'ri_ERS, teglar, _id_
{"_id_":"14.1 MB","noto'g'ri_ERS":"6.7 MB","ESR":"6.2 MB","teglar":"2.5 MB"}

_id_ — eng katta: har hujjat uchun bittadan, siqilmagan kalitlar. Compound indekslar uch maydonli bo'lsa ham ikki baravar kichik — WiredTiger indeks kalitlarida prefiks siqish ishlatadi (bir xil egasi takrorlanmaydi; hujjat bo'yicha).

4.1 Ikki massivli compound — taqiqlangan

js
await ikki.insertOne({ a: [1], b: [2] });
await ikki.createIndex({ a: 1, b: 1 });
text
ikki massivli compound — taqiqlangan: Index build failed: a3f713ca-5d3b-4f2f-8ac3-d185a60a0c8c: Collection katta.ikki ( 0f224fe7

Kanon xabarni 90 belgida kesgan; to'liq xabarda sabab — cannot index parallel arrays [b] [a] ("parallel massivlarni indekslab bo'lmaydi", kanon qaydi). Compound indeksda ko'pi bilan bitta maydon massiv bo'lishi mumkin: ikkitasi bo'lsa, kalitlar soni ko'paytmaga aylanib ketadi (3 × 4 = 12 kalit bitta hujjatga). Hujjatda ikkala maydon ham massiv bo'lsa — indeks yaratilmaydi; indeks bor bo'lsa — bunday hujjat yozilmaydi.

5. Text indeks: matn qidiruvi

5.1 O'zbek tili va default_language

Mongo'da to'liq matn qidiruvi uchun text indeks bor (Postgres full-text search ning o'xshashi):

js
await K.createIndex(
  { matn: "text" },
  { name: "matn_text", default_language: "none" },
);
await K.find({ $text: { $search: "hisobot 12345" } })
  .explain("executionStats");

default_language: "none" — o'zbek tili Mongo'ning stemming ro'yxatida yo'q (ingliz, rus, turk va boshqalar bor — hujjat bo'yicha). "none" — so'zlarni o'zgartirmasdan, faqat bo'laklarga bo'lib indekslash. Inglizcha sukutda esa Mongo o'zbekcha so'zlarga ingliz qoidalarini qo'llab, ularni buzishi mumkin.

text
{"$text":{"reja":"TEXT_MATCH(matn_text) ← FETCH ← OR","natija":50064,"kalitlar":50064,"hujjatlar":50064,"ms":112}}

50 064 natija! "hisobot 12345" ni yozdik, kutganimiz — bir nechta vazifa. Reja boshida — OR. $text sukut bo'yicha so'zlar orasida YOKI qo'yadi: "hisobot" so'zi bor hamma vazifa (katta to'plamda ular ko'p). Hamma so'z bo'lishi kerak bo'lsa — har so'zni qo'shtirnoqqa olish (fraza) kerak.

5.2 Apostrof tuzog'i

js
await K.countDocuments({ $text: { $search: "to'lov" } });
await K.countDocuments({ $text: { $search: "tolov" } });
await K.countDocuments({ $text: { $search: "\"to'lov qilish\"" } });
text
$text 'to''lov': 94810 | 'tolov': 0 | '"to''lov qilish"' (fraza): 49699
  • to'lov — 94 810. Kanon izohi: apostrof so'zni bo'ladi — to va lov alohida so'z, va to juda ko'p matnga mos keladi (OR).
  • tolov — 0. Apostrofsiz yozilsa — topmaydi: stemming yo'q, o'xshashlik yo'q.
  • Fraza ("to'lov qilish" qo'shtirnoqda) — 49 699: aniq ketma-ketlik.

O'zbek matnida o', g' va tutuq belgisi juda ko'p — text indeks ularni so'z chegarasi deb biladi. Postgres'da bu muammoni o'zbekcha FTS konfiguratsiyasi bilan hal qilgandik (Postgres'da full-text search). Mongo'da jiddiy o'zbekcha qidiruv uchun — Atlas Search (sinalmagan) yoki alohida qidiruv tizimi.

5.3 $regex text indeksni ishlatmaydi

js
await K.find({ matn: { $regex: "^Hisobot yozish 1234" } })
  .explain("executionStats");
text
{"$regex ^ (indeks emas — text indeksdan foydalanmaydi)":{"reja":"COLLSCAN","natija":11,"kalitlar":0,"hujjatlar":500000,"ms":521}}

COLLSCAN, 521 ms. Text indeks — so'zlar ro'yxati, satr boshi bo'yicha qidiruvga yaramaydi. ^ bilan boshlangan, katta-kichik harfga sezgir $regex ni oddiy indeks ({ matn: 1 }) tezlashtira oladi (hujjat bo'yicha; kanonda bunday indeks yo'q edi). i (harf farqsiz) yoki o'rtadagi naqsh (/yozish/) — oddiy indeks bilan ham butun skan.

6. unique, partial va TTL

Kanon bu uchtasini kichik sessiyalar kolleksiyasida sinadi:

js
await S.createIndex({ token: 1 }, { unique: true });
await S.createIndex(
  { yaratilgan: 1 }, { expireAfterSeconds: 2 });
await S.createIndex({ email: 1 }, {
  unique: true,
  partialFilterExpression: { email: { $type: "string" } },
});

6.1 unique

text
unique takror: 11000 E11000 duplicate key error collection: katta.sessiyalar index: token_1

Bu Mongoose schema darsida ko'rgan 11000 xatosining manbai: noyob indeks. Xabarda indeks nomi (token_1 — maydon nomi + yo'nalish, avtomatik).

6.2 partial unique

text
partial unique: email'siz ikki hujjat — o'tdi ; bir xil email — xato 11000

Oddiy unique da email'siz ikki hujjat bo'lsa — ikkinchisi xato beradi: "maydon yo'q" ham qiymat sifatida (null) indekslanadi va takrorlanadi. Partial indeks faqat partialFilterExpression ga mos hujjatlarni indekslaydi: email satr bo'lganlarini. Email'sizlar indeksga kirmaydi — cheklov ularga tegmaydi. Postgres'dagi CREATE UNIQUE INDEX … WHERE email IS NOT NULL ning o'xshashi (Partial, expression va covering indekslar).

6.3 TTL — o'zini o'chiradigan hujjatlar

TTL (time to live — "yashash muddati") — hujjat avtomatik o'chishiga qadar yashaydigan vaqt. Redis darslarida xuddi shu atama kalitlar uchun ishlatiladi (String, TTL va kalit nomlash).

expireAfterSeconds: 2 — yaratilgan sanasidan 2 soniya o'tgan hujjat avtomatik o'chiriladi. Sessiya, tasdiqlash kodi, vaqtinchalik token uchun ideal. Kanon hujjatlar qachon yo'qolishini kutib o'lchadi:

text
TTL: 2 s muddatli hujjatlar 37 s da o'chdi (TTL monitor ~60 s da bir ishlaydi)

Nima bo'ldi? 2 soniya emas — 37 soniya! TTL o'chirishni server ichidagi fon jarayoni (TTL monitor) qiladi va u taxminan 60 soniyada bir ishlaydi (hujjat bo'yicha). Shuning uchun muddati o'tgan hujjat yana bir daqiqagacha bazada qolishi mumkin.

Amaliy natija: TTL — tozalash vositasi, xavfsizlik chegarasi emas. 5 daqiqalik SMS kodini tekshirishda faqat TTL'ga tayanmang — so'rovda ham yaratilgan > hozir - 5 daqiqa ni tekshiring. TTL maydoni BSON Date bo'lishi shart: satr sana bo'lsa, hujjat hech qachon o'chmaydi (hujjat bo'yicha).

7. Indeksning narxi: yozish

Har indeks — har insert, update, delete da yangilanadigan qo'shimcha tuzilma. Kanon 20 000 hujjatni ikki holatda yozdi:

text
20 000 hujjat: faqat _id 398 ms, +6 indeks (text bilan) 921 ms
20 000 hujjat insertMany: indekslar soni
  • Faqat _id398 ms
  • _id + 6 indeks (text bilan)921 ms

Manba: IlmHamroh kanon o'lchovi, 2026-10-25: MongoDB 8.3.13 (Docker, WSL2), mongodb 7.7.0, Node 24.21.0, i5-12500H; bitta o'lchov

2.3 baravar sekin. Text indeks ayniqsa qimmat: har hujjatning har so'zi — alohida kalit. Indeks qo'shishdan oldin savol bering: bu so'rov qanchalik tez-tez ishlaydi va indekssiz qanchalik sekin? Ishlatilmayotgan indeksni topish uchun $indexStats (kanon indeks nomlarini shu bilan o'qigan) foydalanish hisoblagichini ko'rsatadi.

Butun dars xulosasi bitta grafikda:

Bir xil so'rov (egasi 77, oxirgi 20): ko'rilgan hujjatlar
  • Indekssiz (COLLSCAN)500 000 hujjat
  • Range saralashdan oldin (SORT)344 hujjat
  • E-R-S tartib20 hujjat
  • ESR20 hujjat

Manba: IlmHamroh kanon o'lchovi, 2026-10-25: MongoDB 8.3.13, 500 000 hujjat, explain executionStats (totalDocsExamined)

E-R-S va ESR ikkalasi ham 20 hujjat o'qidi, farqi kalitlarda (43 va 20) — grafikda ko'rinmaydi, lekin o'sish bilan farq ham o'sadi.

8. Loyiha qadami: kanon tajribasi, loyihaga kirmaydi

vazifalar-api indekslari Postgres'da (26-qism: (egasi_id, …) tarkibiy indekslar, keyset uchun). Kanon Mongo'da (500 000 hujjat):

  1. COLLSCAN 353 ms → ESR 20 kalit / 20 hujjat; planner ESR'ni o'zi tanladi.
  2. Range saralashdan oldin — xotirada SORT (344 kalit).
  3. Multikey, ikki massivli compound taqiqi, indeks hajmlari.
  4. Text indeks: sukut OR, apostrof to'lov → to + lov, $regex COLLSCAN.
  5. unique E11000, partial unique, TTL 37 s; yozish narxi 398 → 921 ms.

9. Ko'p uchraydigan xatolar

Xato Oqibat To'g'risi
Compound indeksda diapazon maydoni oldinda Ortiqcha kalitlar yoki xotirada SORT ESR: tenglik, saralash, diapazon
Faqat ms ga qarash Kichik bazada hamma narsa tez totalKeysExamined/totalDocsExamined
Text qidiruvda ko'p so'z OR — minglab natija Fraza ("…") yoki boshqa qidiruv
O'zbek matni uchun sukut til Inglizcha stemming so'zlarni buzadi default_language: "none"
TTL'ni aniq muddat deb bilish Hujjat ~60 s qolib ketadi So'rovda ham vaqtni tekshiring
TTL maydoni satr Hujjat hech qachon o'chmaydi BSON Date
Har maydonga indeks Yozish 2–3 baravar sekin Faqat haqiqiy so'rovlar uchun
Ixtiyoriy maydonga oddiy unique Ikkinchi "yo'q" qiymat 11000 beradi partialFilterExpression

10. Mashqlar

Mashqlar kurs/mashqlar/27/49-indekslar/ da. 2- va 3-mashq yechimlari Node 24 da tekshirilgan (biz ishga tushirdik, bazasiz).

1-mashq (oson): to'ldiring

  • Butun kolleksiya skani bosqichi —
  • ESR'dagi E —
  • Massiv maydondagi indeks turi —
  • TTL indeks sozlamasi — expireAfter
  • Kanonda 2 s TTL hujjatlari necha soniyada o'chdi?
Yechim
  • COLLSCAN — Postgres'dagi Seq Scan.
  • Equality — keyin Sort, keyin Range.
  • multikey — har element alohida kalit; compound'da faqat bitta massiv.
  • Seconds — expireAfterSeconds.
  • 37 — TTL monitor taxminan 60 s da bir ishlaydi.

2-mashq (o'rta): ESR tartibini hisoblash

esrIndeks(filtr, sort) funksiyasini yozing: compound indeks obyektini ESR qoidasi bo'yicha qaytarsin. Filtrdagi oddiy qiymat — tenglik; operator obyekti ({ $gte: … }, { $in: … }) — diapazon. Saralash maydonlari — ularning yo'nalishi bilan; diapazon maydonlari 1. Maydon ham saralashda, ham diapazonda bo'lsa — bir marta, saralash joyida. Kanon so'rovi va «Range saralashdan oldin» holati bilan sinang.

Ishora: obyekt kalitlari qo'shilish tartibini saqlaydi.

Yechim
js
function esrIndeks(filtr, sort = {}) {
  const E = [], R = [];
  for (const [k, v] of Object.entries(filtr)) {
    const operator = v !== null && typeof v === "object"
      && !(v instanceof Date) && !Array.isArray(v);
    (operator ? R : E).push(k);
  }
  const indeks = {};
  for (const k of E) indeks[k] = 1;
  for (const [k, yon] of Object.entries(sort)) {
    if (!(k in indeks)) indeks[k] = yon;
  }
  for (const k of R) if (!(k in indeks)) indeks[k] = 1;
  return indeks;
}

const yil = new Date("2025-01-01");
console.log(esrIndeks(
  { egasi: 77, bajarildi: false, yaratilgan: { $gte: yil } },
  { yaratilgan: -1 },
));
console.log(esrIndeks(
  { egasi: 77, yaratilgan: { $gte: yil } },
  { ustuvorlik: 1 },
));
console.log(esrIndeks(
  { holat: "yangi", narx: { $lt: 50000 } }, { sana: -1 },
));

Konsolda:

text
{ egasi: 1, bajarildi: 1, yaratilgan: -1 }
{ egasi: 1, ustuvorlik: 1, yaratilgan: 1 }
{ holat: 1, sana: -1, narx: 1 }

Birinchi natija — kanondagi ESR indeksining aynan o'zi. Ikkinchisi — «Range saralashdan oldin» holatidagi xotiradagi SORT'ni yo'qotadigan indeks. Uchinchisi — «Tekshirib ko'ring» savolining javobi. Haqiqiy loyihada bu faqat boshlang'ich taxmin — so'ng explain bilan tekshiriladi.

3-mashq (qiyin): explain hisobotini o'qish

baho(nom, stat) funksiyasini yozing. stat — kanon formatidagi obyekt (reja, natija, kalitlar, hujjatlar). Qaytarsin: "<nom>: <xulosa>", bunda xulosa:

  • reja COLLSCAN ni o'z ichiga olsa — "COLLSCAN — indeks kerak";
  • reja SORT bilan boshlansa — "xotirada SORT — ESR'ni tekshiring";
  • kalitlar / natija > 1.5 — "ortiqcha kalit: <nisbat>x" (bir xona aniqlikda);
  • aks holda — "yaxshi".

Kanondagi beshta natija bilan sinang.

Ishora: toFixed(1) va startsWith — satr metodlari.

Yechim
js
function baho(nom, s) {
  let xulosa;
  if (s.reja.includes("COLLSCAN")) xulosa = "COLLSCAN — indeks kerak";
  else if (s.reja.startsWith("SORT")) {
    xulosa = "xotirada SORT — ESR'ni tekshiring";
  } else if (s.kalitlar / s.natija > 1.5) {
    xulosa = `ortiqcha kalit: ${(s.kalitlar / s.natija).toFixed(1)}x`;
  } else xulosa = "yaxshi";
  return `${nom}: ${xulosa}`;
}

const kanon = {
  indekssiz: { reja: "SORT ← COLLSCAN", natija: 20,
    kalitlar: 0, hujjatlar: 500000 },
  "E_R_S tartib": { reja: "LIMIT ← FETCH ← IXSCAN(noto'g'ri_ERS)",
    natija: 20, kalitlar: 43, hujjatlar: 20 },
  ESR: { reja: "LIMIT ← FETCH ← IXSCAN(ESR)", natija: 20,
    kalitlar: 20, hujjatlar: 20 },
  "SORT xotirada": { reja: "SORT ← FETCH ← IXSCAN(noto'g'ri_ERS)",
    natija: 20, kalitlar: 344, hujjatlar: 344 },
  "teg multikey": { reja: "FETCH ← IXSCAN(noto'g'ri_ERS)",
    natija: 42, kalitlar: 401, hujjatlar: 401 },
};
for (const [nom, s] of Object.entries(kanon)) {
  console.log(baho(nom, s));
}

Konsolda:

text
indekssiz: COLLSCAN — indeks kerak
E_R_S tartib: ortiqcha kalit: 2.1x
ESR: yaxshi
SORT xotirada: xotirada SORT — ESR'ni tekshiring
teg multikey: ortiqcha kalit: 9.5x

Tartib muhim: SORT ← COLLSCAN da birinchi muammo — COLLSCAN. Oxirgi qator: 401 kalitdan 42 natija — teglar sharti uchun mos compound indeks ({ egasi: 1, teglar: 1 }) yo'q; planner egasi indeksini oldi va tegni hujjatlarda tekshirdi. Bunday "kichik avtomatik auditor" — real loyihada sekin so'rovlar logini tahlil qilishning boshlanishi.

11. Real ishda

  • Sekin so'rov — Mongo'li loyihadagi eng ko'p muammo; profiler (db.setProfilingLevel) va Atlas Performance Advisor sekin so'rovlarni ko'rsatadi (hujjat bo'yicha, sinalmagan), tuzatish — explain + ESR.
  • TTL — sessiyalar, tasdiqlash kodlari, vaqtinchalik fayl yozuvlari, log'larni avtomatik tozalash.
  • Text indeks — oddiy qidiruv uchun; o'zbek tilida cheklovlari katta — jiddiy qidiruv uchun Atlas Search, Elasticsearch yoki Postgres FTS.
  • Intervyu savollari: "ESR qoidasi nima?", "multikey indeks qanday ishlaydi?", "TTL hujjatni aniq vaqtda o'chiradimi?", "nega har maydonga indeks qo'yilmaydi?".

Xulosa

  • explain("executionStats"): COLLSCAN/IXSCAN/FETCH/SORT; asosiy ko'rsatkich — ko'rilgan kalit va hujjatlar natijaga nisbatan.
  • Compound indeks — ESR: Equality, Sort, Range; kanonda COLLSCAN 500 000 hujjat → ESR 20 kalit, 20 hujjat.
  • Diapazon saralashdan oldin bo'lsa — xotirada SORT (344 kalit); planner to'g'ri indeksni o'zi tanlay oladi.
  • Multikey — har element kalit, compound'da faqat bitta massiv; text — default_language: "none", sukut OR, apostrof so'zni bo'ladi; $regex text indeksni ishlatmaydi.
  • unique → E11000; partial — faqat mos hujjatlar indekslanadi; TTL ~60 s davriy (kanon: 37 s).
  • Indeks yozishni sekinlashtiradi: 398 → 921 ms (+6 indeks).

Keyingi dars: MongoDB sxema dizayn naqshlari — 16 MB chegara, cheksiz massiv anti-naqshi, subset, computed, bucket, extended reference va schema versioning o'lchovlar bilan.

Manbalar

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
MongoDB indekslari: COLLSCAN va IXSCAN, ESR qoidasi, multikey, text, TTL va partial — IlmHamroh