13-bo‘lim
Indekslar va so'rov optimizatsiyasi
Indeks qanday ishlaydi, turlari, tarkibiy indekslar, EXPLAIN o'qish va sekin so'rovlarni tezlashtirish.
Ushbu bo‘lim mundarijasi
- Indeks nima?
- Farqni o'lchash
- Indeks turlari
- Qaysi ustunlarga indeks kerak?
- Tarkibiy indekslar
- Indeksni buzadigan so'rovlar
- EXPLAIN - so'rovni tahlil qilish
- Muhim ustunlar
- type qiymatlari - yaxshidan yomonga
- Extra ustunidagi ogohlantirishlar
- Qoplovchi indeks (covering index)
- To'liq matnli qidiruv
- Sekin so'rovlarni topish
- Optimizatsiya ro'yxati
- Amaliy misol
- Xulosa
Indeks - bazani yuzlab barobar tezlashtiradigan yagona eng muhim vosita.
Indeks nima? #
Kitobning oxiridagi alifbo ko'rsatkichini tasavvur qiling. "Algoritm" so'zini topish uchun:
| Usul | Amal |
|---|---|
| Indekssiz | 500 sahifani birma-bir varaqlash |
| Indeks bilan | Ko'rsatkichdan "Algoritm - 42-bet" ni topish |
Bazada ham xuddi shunday.
-- Indekssiz: butun jadval o'qiladi (full table scan)
SELECT * FROM talabalar WHERE email = '[email protected]';
-- Indeks yaratamiz
CREATE INDEX idx_email ON talabalar (email);
-- Endi: to'g'ridan-to'g'ri topiladi
SELECT * FROM talabalar WHERE email = '[email protected]';
Farqni o'lchash #
-- 1 000 000 qatorli jadvalda
SELECT * FROM loglar WHERE foydalanuvchi_id = 12345;
| Holat | O'qilgan qatorlar | Vaqt |
|---|---|---|
| Indekssiz | 1 000 000 | ~850 ms |
| Indeks bilan | ~20 | ~2 ms |
400 barobar farq.
Indeks turlari #
-- Oddiy indeks
CREATE INDEX idx_shahar ON talabalar (shahar);
-- Noyob indeks (takrorlanishga yo'l qo'ymaydi)
CREATE UNIQUE INDEX uq_email ON talabalar (email);
-- Tarkibiy (bir necha ustun)
CREATE INDEX idx_shahar_baho ON talabalar (shahar, ortacha_baho);
-- To'liq matnli qidiruv
CREATE FULLTEXT INDEX ft_matn ON maqolalar (sarlavha, matn);
-- Jadval yaratishda
CREATE TABLE talabalar (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(190) NOT NULL,
shahar VARCHAR(60),
UNIQUE KEY uq_email (email),
KEY idx_shahar (shahar)
) ENGINE=InnoDB;
-- Ko'rish va o'chirish
SHOW INDEX FROM talabalar;
DROP INDEX idx_shahar ON talabalar;
PRIMARY KEY avtomatik indeksBirlamchi kalit har doim indekslanadi. UNIQUE cheklovi ham indeks yaratadi.
FOREIGN KEY esa MySQL da avtomatik indeks qo'shadi.
Qaysi ustunlarga indeks kerak? #
| Ustun | Indeks kerakmi |
|---|---|
WHERE da tez-tez ishlatiladigan | Ha |
JOIN da bog'lanadigan (FK) | Ha, majburiy |
ORDER BY da saralanadigan | Ha |
GROUP BY da guruhlanadigan | Ha |
Faqat SELECT da ko'rsatiladigan | Yo'q |
Kam noyob qiymatli (jins, faolmi) | Odatda yo'q |
| Tez-tez o'zgaradigan | Ehtiyotkorlik bilan |
Har bir indeks:
| Narx | Izoh |
|---|---|
| Xotira | Alohida tuzilma saqlanadi |
INSERT sekinlashadi | Har bir indeks yangilanadi |
UPDATE sekinlashadi | Indekslangan ustun o'zgarsa |
DELETE sekinlashadi | Indeksdan ham o'chiriladi |
10 ta indeksli jadvalda INSERT indekssizdan 3-5 barobar sekin bo'ladi.
Qoida: kerakli indekslarni qo'ying, ortiqchasini o'chiring.
Tarkibiy indekslar #
CREATE INDEX idx_shahar_baho ON talabalar (shahar, ortacha_baho);
Bu indeks quyidagi so'rovlarda ishlaydi:
WHERE shahar = 'Toshkent'
WHERE shahar = 'Toshkent' AND ortacha_baho > 4.0
WHERE shahar = 'Toshkent' ORDER BY ortacha_baho
Lekin bularda ishlamaydi:
WHERE ortacha_baho > 4.0 -- birinchi ustun yo'q
WHERE ortacha_baho > 4.0 AND shahar = 'X' -- ishlaydi (tartib muhim emas)
(a, b, c) indeksi quyidagi kombinatsiyalarda ishlaydi:
aa, ba, b, c
Lekin bularda ishlamaydi:
bcb, c
Telefon kitobi bilan solishtiring: u familiya, keyin ism bo'yicha saralangan. Familiya bo'yicha topish oson, faqat ism bo'yicha - imkonsiz.
Ustunlar tartibi juda muhim: eng ko'p filtrlanadigani birinchi bo'lsin.
Indeksni buzadigan so'rovlar #
-- 1. Ustunga funksiya qo'llash
WHERE YEAR(yaratilgan) = 2026 -- indeks ISHLAMAYDI
WHERE yaratilgan >= '2026-01-01'
AND yaratilgan < '2027-01-01' -- indeks ISHLAYDI
-- 2. Ustun ustida arifmetika
WHERE narx * 1.12 > 100000 -- ISHLAMAYDI
WHERE narx > 100000 / 1.12 -- ISHLAYDI
-- 3. LIKE boshida %
WHERE ism LIKE '%noza' -- ISHLAMAYDI
WHERE ism LIKE 'Dil%' -- ISHLAYDI
-- 4. Tur nomuvofiqligi
WHERE telefon_raqami = 998901234567 -- ustun VARCHAR bo'lsa ISHLAMAYDI
WHERE telefon_raqami = '998901234567' -- ISHLAYDI
-- 5. OR bilan turli ustunlar
WHERE shahar = 'Toshkent' OR email = '[email protected]' -- ko'pincha ISHLAMAYDI
-- Yechim: UNION bilan bo'lish
Umumiy qoida: indekslangan ustunni chap tomonda toza qoldiring.
EXPLAIN - so'rovni tahlil qilish #
EXPLAIN SELECT * FROM talabalar WHERE shahar = 'Toshkent';
+----+-------------+-----------+------+---------------+------------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------+------------+---------+-------+------+-------+
| 1 | SIMPLE | talabalar | ref | idx_shahar | idx_shahar | 183 | const | 2 | |
+----+-------------+-----------+------+---------------+------------+---------+-------+------+-------+
Muhim ustunlar #
| Ustun | Ma'nosi |
|---|---|
type | Qanday qidirilmoqda (eng muhim) |
key | Qaysi indeks ishlatilmoqda |
rows | Necha qator o'qiladi (taxminan) |
Extra | Qo'shimcha amallar |
type qiymatlari - yaxshidan yomonga #
| Qiymat | Ma'nosi | Baho |
|---|---|---|
const | Birlamchi kalit bo'yicha, 1 ta qator | Ajoyib |
eq_ref | Har bir qator uchun 1 ta mos | Ajoyib |
ref | Indeks bo'yicha bir nechta qator | Yaxshi |
range | Indeks bo'yicha oraliq | Yaxshi |
index | Butun indeks o'qiladi | O'rtacha |
ALL | Butun jadval o'qiladi | Yomon |
type: ALL ko'rsangizBu to'liq jadval skanerlash degani. Kichik jadvalda muammo emas, lekin katta jadvalda - asosiy sekinlik sababi.
Yechim: WHERE dagi ustunga indeks qo'shing.
Extra ustunidagi ogohlantirishlar #
| Qiymat | Ma'nosi |
|---|---|
Using index | Ajoyib - faqat indeksdan o'qildi |
Using where | Normal |
Using filesort | Qo'shimcha saralash - indeks yo'q |
Using temporary | Vaqtinchalik jadval yaratildi - sekin |
-- Batafsil tahlil (MySQL 8.0+)
EXPLAIN ANALYZE SELECT ... ;
-- JSON formatida
EXPLAIN FORMAT=JSON SELECT ... ;
Qoplovchi indeks (covering index) #
Agar indeks so'rovga kerakli barcha ustunlarni o'z ichiga olsa, baza jadvalga umuman murojaat qilmaydi:
CREATE INDEX idx_shahar_ism ON talabalar (shahar, ism);
-- Bu so'rov faqat indeksdan o'qiydi - juda tez
SELECT ism FROM talabalar WHERE shahar = 'Toshkent';
Extra: Using index
Using index - eng yaxshi natijaBu "jadvalga murojaat qilinmadi, hammasi indeksdan olindi" degani. Bunday so'rovlar odatdagidan bir necha barobar tez ishlaydi.
Aynan shuning uchun SELECT * yomon: u har doim jadvalga murojaat qilishga majbur qiladi.
To'liq matnli qidiruv #
LIKE '%matn%' sekin. Katta matnlar uchun FULLTEXT:
ALTER TABLE maqolalar ADD FULLTEXT INDEX ft_qidiruv (sarlavha, matn);
SELECT sarlavha,
MATCH(sarlavha, matn) AGAINST('python algoritm') AS ball
FROM maqolalar
WHERE MATCH(sarlavha, matn) AGAINST('python algoritm')
ORDER BY ball DESC;
-- Mantiqiy rejim
SELECT * FROM maqolalar
WHERE MATCH(sarlavha, matn)
AGAINST('+python -java' IN BOOLEAN MODE);
| Belgi | Ma'nosi |
|---|---|
+soz | Majburiy |
-soz | Bo'lmasin |
"ibora" | Aniq ibora |
soz* | Prefiks bo'yicha |
Sekin so'rovlarni topish #
-- Sekin so'rovlar jurnalini yoqish
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1; -- 1 soniyadan uzun
-- Hozir bajarilayotgan so'rovlar
SHOW PROCESSLIST;
-- Indekslar hajmi
SELECT
table_name,
ROUND(data_length / 1024 / 1024, 1) AS malumot_mb,
ROUND(index_length / 1024 / 1024, 1) AS indeks_mb
FROM information_schema.TABLES
WHERE table_schema = 'maktab'
ORDER BY index_length DESC;
Optimizatsiya ro'yxati #
EXPLAINbilan boshlang -type: ALLbormi?WHERE,JOIN,ORDER BYustunlariga indeks qo'shing- Ustunga funksiya qo'llashni olib tashlang
SELECT *o'rniga kerakli ustunlarni sanangLIMITqo'ying- Bog'langan ichki so'rovni
JOINga aylantiring LIKE '%...'o'rnigaFULLTEXTishlating- Tarkibiy indeksda ustunlar tartibini tekshiring
Amaliy misol #
-- Sekin so'rov
EXPLAIN SELECT * FROM buyurtmalar
WHERE YEAR(yaratilgan) = 2026 AND holat = 'yangi'
ORDER BY yaratilgan DESC;
-- type: ALL, rows: 500000, Extra: Using filesort
-- 1-tuzatish: funksiyani olib tashlash
-- 2-tuzatish: tarkibiy indeks
CREATE INDEX idx_holat_sana ON buyurtmalar (holat, yaratilgan);
EXPLAIN SELECT id, mijoz_id, summa, yaratilgan
FROM buyurtmalar
WHERE holat = 'yangi'
AND yaratilgan >= '2026-01-01'
AND yaratilgan < '2027-01-01'
ORDER BY yaratilgan DESC
LIMIT 50;
-- type: range, rows: 1200, Extra: Using where
Natija: 500 000 qator o'rniga 1 200 - 400 barobar kam ish.
kutubxonabazasidagi barcha so'rovlaringizgaEXPLAINqo'llang.type: ALLbo'lganlarini toping.kitoblarjadvalidagimuallif_idvajanrustunlariga indeks qo'shing.EXPLAINni qayta bajarib,typevarowsqanday o'zgarganini yozing.(janr, yil)tarkibiy indeksini yarating va uch xil so'rovda sinang: faqatjanr, faqatyil, ikkalasi birga.- Qoplovchi indeks yarating va
Using indexchiqishiga erishing. WHERE YEAR(yil) = 2020vaWHERE yil = 2020ni solishtiring.SHOW INDEX FROM kitoblar;bilan barcha indekslarni ko'ring.
Xulosa #
- Indeks - B-daraxt tuzilmasi; qidiruvni O(n) dan O(log n) ga tushiradi.
WHERE,JOIN,ORDER BY,GROUP BYustunlariga indeks kerak.- Indeks bepul emas:
INSERT/UPDATEsekinlashadi va xotira sarflanadi. - Tarkibiy indeksda "chapdan prefiks" qoidasi amal qiladi - tartib muhim.
- Ustunga funksiya qo'llash indeksni buzadi.
EXPLAIN- asosiy tahlil vositasi;type: ALLyomon,Using indexajoyib.- Qoplovchi indeks jadvalga murojaatni butunlay yo'q qiladi.
- Matn qidiruvi uchun
LIKE '%...'emas,FULLTEXTishlating.
Keyingi bo'limda MySQL ning o'rnatilgan funksiyalarini o'rganamiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.