Mundarija (29)
- Bu darsda
- 1. Nega bu kerak?
- 2. explain: so'rov qanday bajarildi
- 2.1 Indekssiz
- 2.2 Bosqich nomlari
- 3. Compound indeks va ESR qoidasi
- 3.1 Noto'g'ri tartib: E–R–S
- 3.2 ESR: Equality, Sort, Range
- 3.3 Range saralashdan oldin bo'lsa
- 4. Multikey: massivga indeks
- 4.1 Ikki massivli compound — taqiqlangan
- 5. Text indeks: matn qidiruvi
- 5.1 O'zbek tili va default_language
- 5.2 Apostrof tuzog'i
- 5.3 $regex text indeksni ishlatmaydi
- 6. unique, partial va TTL
- 6.1 unique
- 6.2 partial unique
- 6.3 TTL — o'zini o'chiradigan hujjatlar
- 7. Indeksning narxi: yozish
- 8. Loyiha qadami: kanon tajribasi, loyihaga kirmaydi
- 9. Ko'p uchraydigan xatolar
- 10. Mashqlar
- 1-mashq (oson): to'ldiring
- 2-mashq (o'rta): ESR tartibini hisoblash
- 3-mashq (qiyin): explain hisobotini o'qish
- 11. Real ishda
- Xulosa
- Manbalar
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:
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:
{"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:
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).
{"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
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{"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:
- E — Equality (tenglik): aniq qiymat bilan solishtiriladigan maydonlar (
egasi: 77,bajarildi: false). - S — Sort (saralash):
sortdagi maydonlar. - R — Range (diapazon):
$gte,$lt,$inkabi.
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:
await K.find({
egasi: 77,
yaratilgan: { $gte: new Date("2025-01-01") },
}).sort({ ustuvorlik: 1 }).limit(20)
.hint("noto'g'ri_ERS").explain("executionStats");{"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.
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");{"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:
- Indekssiz, lekin 58 hujjat.
limit(5)bor: Mongo skanerni boshladi va 58-hujjatda 5 tasportni topib to'xtadi. Tez-tez uchraydigan qiymat + kichik limit — COLLSCAN ham tez. Lekin bu omad: kam uchraydigan teg uchun butun kolleksiya o'qiladi. teglarindeksi bor, planner esanoto'g'ri_ERSni 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 — buniexplaindan bilasiz, taxmindan emas.
Indekslar hajmi (kanon collStats dan):
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
await ikki.insertOne({ a: [1], b: [2] });
await ikki.createIndex({ a: 1, b: 1 });ikki massivli compound — taqiqlangan: Index build failed: a3f713ca-5d3b-4f2f-8ac3-d185a60a0c8c: Collection katta.ikki ( 0f224fe7Kanon 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):
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":{"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
await K.countDocuments({ $text: { $search: "to'lov" } });
await K.countDocuments({ $text: { $search: "tolov" } });
await K.countDocuments({ $text: { $search: "\"to'lov qilish\"" } });$text 'to''lov': 94810 | 'tolov': 0 | '"to''lov qilish"' (fraza): 49699to'lov— 94 810. Kanon izohi: apostrof so'zni bo'ladi —tovalovalohida so'z, vatojuda 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
await K.find({ matn: { $regex: "^Hisobot yozish 1234" } })
.explain("executionStats");{"$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:
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
unique takror: 11000 E11000 duplicate key error collection: katta.sessiyalar index: token_1Bu Mongoose schema darsida ko'rgan 11000 xatosining manbai: noyob indeks. Xabarda indeks nomi (token_1 — maydon nomi + yo'nalish, avtomatik).
6.2 partial unique
partial unique: email'siz ikki hujjat — o'tdi ; bir xil email — xato 11000Oddiy 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:
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:
20 000 hujjat: faqat _id 398 ms, +6 indeks (text bilan) 921 ms- 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:
- 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):
- COLLSCAN 353 ms → ESR 20 kalit / 20 hujjat; planner ESR'ni o'zi tanladi.
- Range saralashdan oldin — xotirada SORT (344 kalit).
- Multikey, ikki massivli compound taqiqi, indeks hajmlari.
- Text indeks: sukut OR, apostrof
to'lov→to+lov,$regexCOLLSCAN. - 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
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:
{ 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
COLLSCANni o'z ichiga olsa —"COLLSCAN — indeks kerak"; - reja
SORTbilan 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
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:
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.5xTartib 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;$regextext 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
- MongoDB 8 hujjati — Indexes: https://www.mongodb.com/docs/manual/indexes/
- MongoDB hujjati — The ESR (Equality, Sort, Range) Guideline: https://www.mongodb.com/docs/manual/tutorial/equality-sort-range-guideline/
- MongoDB hujjati — Multikey Indexes, Text Indexes (
default_language), TTL Indexes, Partial Indexes: https://www.mongodb.com/docs/manual/core/indexes/index-types/ - MongoDB hujjati — Explain Results: https://www.mongodb.com/docs/manual/reference/explain-results/
- Kanon o'lchovi (IlmHamroh, 2026-10): MongoDB 8.3.13 (Docker, WSL2), mongodb 7.7.0, Node 24.21.0, i5-12500H, 500 000 hujjat. Mashq yechimlari — biz ishga tushirdik (Node 24.21.0).
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!