Index turlari — PRIMARY, UNIQUE, COMPOSITE, FULLTEXT
Muammodan boshlaylik
O'tgan darsda oddiy indeksni ko'rdik. Lekin real so'rovlar murakkabroq:
-- Mijozning yetkazilmagan buyurtmalari, eng yangisi birinchi
SELECT * FROM buyurtmalar
WHERE mijoz_id = 42 AND holat = 'yangi'
ORDER BY yaratilgan DESC;
-- Mahsulot nomida va tavsifida "simsiz quloqchin" qidiruvi
SELECT * FROM mahsulotlar WHERE tavsif LIKE '%simsiz%quloqchin%';
Uchta alohida indeks yaratish (mijoz_id, holat, yaratilgan) — birinchi so'rov uchun yetarli emas. Ikkinchisi uchun oddiy indeks umuman ishlamaydi. Har bir vazifaga — o'z indeks turi.
PRIMARY KEY
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY
- Jadvalda bitta,
NOT NULL+UNIQUE - InnoDB da — clustered: jadvalning o'zi shu tartibda saqlanadi (30-dars)
- Primary key bo'lmasa, InnoDB yashirin 6 baytlik ID yaratadi — doim o'zingiz bering
Nima uchun AUTO_INCREMENT yaxshi primary key? Har yangi qator jadval oxiriga qo'shiladi — B-tree tartibli o'sadi. Tasodifiy qiymat (masalan, UUID v4) esa har safar daraxtning o'rtasiga tushadi — sahifalar bo'linadi, yozish sekinlashadi, jadval "parchalanadi". UUID kerak bo'lsa — vaqtga asoslangan UUID v7 yoki UUID_TO_BIN(UUID(), 1).
UNIQUE
CREATE UNIQUE INDEX uq_mijozlar_email ON mijozlar (email);
-- yoki
ALTER TABLE mijozlar ADD CONSTRAINT uq_email UNIQUE (email);
Ikki vazifa birdan:
- Cheklov — takror qiymat kira olmaydi (6-dars)
- Indeks —
WHERE email = ?tez
Login so'rovi WHERE email = ? — UNIQUE indeks tufayli bir zumda.
COMPOSITE — bir nechta ustunli indeks
CREATE INDEX idx_buyurtma_mijoz_holat_vaqt
ON buyurtmalar (mijoz_id, holat, yaratilgan);
Indeks qiymatlari ustunlar tartibida saralanadi — telefon kitobi kabi: avval familiya, keyin ism, keyin otasining ismi.
(mijoz_id, holat, yaratilgan)
(42, 'bekor', 2026-03-01)
(42, 'yangi', 2026-09-10)
(42, 'yangi', 2026-10-25) ← mijoz 42, yangi — shu yerda, vaqt bo'yicha tartiblangan
(42, 'yetkazildi', ...)
(43, ...)
WHERE mijoz_id = 42 AND holat = 'yangi' ORDER BY yaratilgan DESC — MySQL kerakli joyga sakraydi va natijalar allaqachon tartiblangan. Alohida saralash shart emas.
Chap prefiks qoidasi
Composite indeks faqat chapdan boshlab ishlaydi:
| So'rov sharti | (mijoz_id, holat, yaratilgan) ishlaydimi? |
|---|---|
mijoz_id = 42 |
✅ |
mijoz_id = 42 AND holat = 'yangi' |
✅ |
mijoz_id = 42 AND holat = 'yangi' AND yaratilgan > ... |
✅ |
mijoz_id = 42 ORDER BY holat |
✅ |
holat = 'yangi' |
❌ — mijoz_id o'tkazib yuborildi |
yaratilgan > '2026-10-01' |
❌ |
mijoz_id = 42 AND yaratilgan > ... |
⚠️ faqat mijoz_id qismi |
Telefon kitobidan "ismi Aziz bo'lganlar"ni (familiyasiz) topib bo'lmaydi — kitob familiya bo'yicha tartiblangan.
Shuning uchun (a, b) indeks bo'lsa, alohida (a) indeks keraksiz — (a, b) uning ishini ham bajaradi.
Ustunlar tartibini tanlash
- Tenglik (
=) shartlari — birinchi - Oraliq (
>,<,BETWEEN) yokiORDER BY— oxirida - Teng holatda — ko'proq so'rovlarda ishlatiladigani chapda
-- So'rov: WHERE holat = ? AND yaratilgan > ?
CREATE INDEX idx_holat_vaqt ON buyurtmalar (holat, yaratilgan); -- ✅
CREATE INDEX idx_vaqt_holat ON buyurtmalar (yaratilgan, holat); -- ❌ oraliqdan keyin holat ishlamaydi
Covering index — jadvalga umuman kirmaslik
Agar so'rovga kerakli barcha ustunlar indeksda bo'lsa — MySQL jadvalning o'ziga murojaat qilmaydi:
CREATE INDEX idx_mijoz_holat ON buyurtmalar (mijoz_id, holat);
SELECT holat, COUNT(*) FROM buyurtmalar WHERE mijoz_id = 42 GROUP BY holat;
mijoz_id va holat — ikkalasi ham indeksda. EXPLAIN da Extra: Using index — eng yaxshi holat. Secondary indeks → primary key → qator degan ikkinchi qadam yo'q.
SELECT * esa covering index imkoniyatini yo'qotadi — yana bir sabab ustunlarni sanab yozish uchun.
Prefix index — uzun matnlar uchun
CREATE INDEX idx_url ON sahifalar (url(100));
Uzun VARCHAR / TEXT ning faqat birinchi 100 belgisi indekslanadi. TEXT ustunlarga oddiy indeks qo'yishning yagona yo'li.
Functional index (MySQL 8.0.13+)
30-darsda: WHERE LOWER(email) = ? indeksni ishlatmaydi. MySQL 8 da ifodaning o'zini indekslash mumkin:
CREATE INDEX idx_email_lower ON mijozlar ((LOWER(email))); -- ikki qavat qavs!
SELECT * FROM mijozlar WHERE LOWER(email) = 'aziz@mail.uz'; -- ✅ endi indeks ishlaydi
CREATE INDEX idx_yil ON buyurtmalar ((YEAR(yaratilgan)));
So'rovdagi ifoda indeksdagi bilan aynan mos bo'lishi kerak.
FULLTEXT — matn bo'yicha qidiruv
LIKE '%so'z%' — sekin (indeks ishlamaydi) va aqlsiz ("quloqchin" so'rasangiz "quloqchinlar" ni topmaydi, natijalarni muvofiqlik bo'yicha saralamaydi).
ALTER TABLE mahsulotlar ADD COLUMN tavsif TEXT;
CREATE FULLTEXT INDEX ft_mahsulot ON mahsulotlar (nom, tavsif);
Natural language mode
SELECT nom, MATCH(nom, tavsif) AGAINST ('simsiz quloqchin') AS muvofiqlik
FROM mahsulotlar
WHERE MATCH(nom, tavsif) AGAINST ('simsiz quloqchin')
ORDER BY muvofiqlik DESC;
So'zlarni alohida topadi va muvofiqlik balli bo'yicha saralaydi — ko'proq mos keladigani birinchi.
Boolean mode
SELECT nom FROM mahsulotlar
WHERE MATCH(nom, tavsif) AGAINST ('+quloqchin -simli' IN BOOLEAN MODE);
| Operator | Ma'nosi |
|---|---|
+so'z |
Albatta bo'lsin |
-so'z |
Bo'lmasin |
so'z* |
Shu bilan boshlansin: quloq* → quloqchin, quloqlar |
"ibora" |
Aynan shu ibora |
Cheklovlar
- Standart holatda 3 belgidan qisqa so'zlar indekslanmaydi (
innodb_ft_min_token_size) - "Stop words" (the, and, is...) e'tiborsiz — inglizcha ro'yxat
- O'zbek tili morfologiyasini tushunmaydi: "kitob" va "kitoblarim" — har xil so'z (
kitob*yordam beradi) - Juda katta va murakkab qidiruv uchun — Elasticsearch, Meilisearch, Typesense
SPATIAL — geografik ma'lumot
CREATE TABLE dokonlar (
id INT PRIMARY KEY,
nom VARCHAR(100),
joy POINT NOT NULL SRID 4326,
SPATIAL INDEX (joy)
);
"Menga eng yaqin 5 ta filial" kabi so'rovlar uchun. Yetkazib berish va xarita ilovalarida.
Indekslar ro'yxati
| Tur | Nima uchun |
|---|---|
PRIMARY KEY |
Qatorning noyob ID si; clustered |
UNIQUE |
Takrorlanmaslik + tez qidiruv |
INDEX |
Oddiy tezlashtirish |
| Composite | Bir nechta ustunli shartlar va ORDER BY |
| Covering | Jadvalga kirmasdan javob |
| Prefix | Uzun matnlar |
| Functional | LOWER(email), YEAR(sana) kabi ifodalar |
FULLTEXT |
So'z bo'yicha matn qidiruvi |
SPATIAL |
Geografik koordinatalar |
Nima uchun shunday?
Nima uchun composite indeksda ustunlar tartibi bunchalik muhim?
Chunki B-tree — bir o'lchovli tartiblangan ro'yxat. (mijoz_id, holat) — avval mijoz_id bo'yicha, bir xil mijoz_id ichida — holat bo'yicha. Barcha "yangi" buyurtmalar ro'yxat bo'ylab tarqalib ketgan: har bir mijozning bo'lagida bittadan. Ularni bir joydan olib bo'lmaydi. Ikki o'lchovli qidiruvni bir o'lchovli tuzilmada bajarish uchun — ustunlar tartibini so'rovga moslab tanlash kerak.
Xulosa
Eslab qoling:
- PRIMARY KEY — clustered, qisqa va ketma-ket (
AUTO_INCREMENT) - UNIQUE — cheklov + indeks
- Composite
(a, b, c)— chap prefiks qoidasi:a,a+b,a+b+cishlaydi;byolg'iz — yo'q - Tartib: tenglik shartlari chapda, oraliq /
ORDER BYo'ngda - Covering index — kerakli hamma ustun indeksda →
Using index - Functional index:
((LOWER(email))) - FULLTEXT:
MATCH ... AGAINST, boolean mode+,-,* (a, b)bor bo'lsa,(a)keraksiz
Keyingi dars
32-dars: EXPLAIN va EXPLAIN ANALYZE — so'rovni tahlil qilish