Сайт ишга тушган пайтда базада бир неча юз қатор бўлади ва ҳар қандай сўров бир зумда бажарилади. Бир-икки йилдан кейин эса буюртмалар, маҳсулотлар ва мижозлар жадвалларида юз минглаб қатор тўпланади, илгари сезилмаган сўровлар эса сониялаб давом эта бошлайди. Кўпинча бунинг сабаби сервер кучсизлигида эмас, балки керакли индекс йўқлигида бўлади. Тўғри қўйилган битта индекс оғир сўровни бир неча баробар, баъзан юзлаб баробар тезлаштириши мумкин.
Индекс нима ва у қандай ишлайди
Индексни китоб охиридаги алифбо кўрсаткичига ўхшатиш мумкин. Керакли мавзуни топиш учун бутун китобни варақлаб чиқмайсиз, кўрсаткичдан саҳифа рақамини топиб, тўғридан-тўғри ўша жойни очасиз. MySQL ҳам индекссиз устун бўйича қидирганда жадвалдаги ҳар бир қаторни бирма-бир текширади, бунга тўлиқ жадвал сканери дейилади. Индекс эса устун қийматларини тартибланган дарахт кўринишида сақлайди ва сервер керакли қаторларга бир неча қадамда етиб боради.
InnoDB жадвалларида асосий калит автоматик равишда индекс ҳисобланади, шунинг учун id бўйича қидирув доим тез. Муаммо бошқа устунлар бўйича қидирилганда бошланади: телефон рақами, ҳолат, категория, сана. Айнан шу устунларга қўшимча индекслар керак бўлади.
Қайси устунларга индекс керак
Индекс қўшиш учун энг яхши номзодлар сўровларда тез-тез ишлатиладиган устунлардир. Улар одатда WHERE шартида фильтрлаш учун, JOIN орқали жадвалларни боғлаш учун ва ORDER BY билан саралаш учун ишлатилади. Қайси сўровлар секин эканини тахмин қилмасдан, секин сўровлар логи ёки илованинг сўров таҳлили воситалари орқали аниқлаб олиш тўғри йўл.
Шу билан бирга, ҳар бир устунга индекс қўйиш ҳам тўғри эмас. Фақат икки-уч хил қиймат қабул қиладиган устун, масалан "фаол" ёки "нофаол" ҳолати, ўзи алоҳида индекс сифатида кам фойда беради, чунки у қаторларнинг ярмини қайтаради. Бундай устун кўпроқ таркибий индекснинг бир қисми сифатида фойдали бўлади.
Муаммони EXPLAIN билан кўриш
Индекс қўшишдан олдин сўровнинг ҳозирги бажарилиш режасини кўриб чиқинг. Қуйидаги мисолда етказиб бериш хизматининг буюртмалар жадвалидан мижоз телефони бўйича қидирилмоқда:
EXPLAIN SELECT id, status, total
FROM orders
WHERE phone = '998901234567'
ORDER BY created_at DESC;
Натижада type устунида ALL, key устунида NULL ва rows устунида жадвалдаги қаторлар сонига яқин рақам кўринса, сервер бутун жадвални кўриб чиқаётган бўлади. Extra устунидаги Using filesort эса натижалар қўшимча равишда алоҳида сараланаётганини билдиради.
Индексни қўшиш
Индекс ALTER TABLE ёки CREATE INDEX буйруғи билан қўшилади. Фильтрлаш ва саралаш бирга ишлатилганда таркибий индекс энг яхши натижа беради: аввал тенглик шарти бўлган устун, кейин саралаш устуни ёзилади. Мавжуд индексларни кўриш учун SHOW INDEX ишлатилади:
SHOW INDEX FROM orders;
ALTER TABLE orders
ADD INDEX idx_phone_created (phone, created_at),
ALGORITHM=INPLACE, LOCK=NONE;
Замонавий MySQL версияларида InnoDB жадвалига иккиламчи индекс қўшиш одатда жадвални ўқиш ва ёзиш учун блокламасдан бажарилади. ALGORITHM=INPLACE, LOCK=NONE қисми буни аниқ талаб қилади: агар шундай бажариб бўлмаса, MySQL жадвални қулфлаш ўрнига хато қайтаради. Шунга қарамай, жуда катта жадвалда индекс қуриш вақт ва қўшимча диск жойини талаб қилади, шунинг учун бу ишни ташрифчилар кам бўлган вақтда ва олдиндан захира нусха олиб бажариш хавфсизроқ.
Таркибий индексда тартиб муҳим
Бир нечта устундан иборат индекс чап томондан бошлаб ишлатилади. (phone, created_at) индекси фақат phone бўйича қидирувга ҳам, phone ва created_at бўйича биргаликдаги сўровга ҳам ёрдам беради. Лекин фақат created_at бўйича қидирилганда бу индекс одатда ишлатилмайди, чунки биринчи устун шартда қатнашмайди. Шунинг учун устунлар тартибини реал сўровларга қараб танлаш керак.
Индексни ишлатиб бўлмайдиган ҳолатлар
Баъзан индекс бор, лекин сўров барибир секин. Бунинг бир нечта одатий сабаблари бор ва уларни билиш кўп вақтни тежайди:
- Устунга функция қўлланганда, масалан
WHERE YEAR(created_at) = 2026, индекс ишламайди. Уни оралиқ кўринишида ёзиш керак:created_at >= '2026-01-01' AND created_at < '2027-01-01'. LIKE '%matn%'каби бошида фоиз белгиси бўлган қидирув оддий индексдан фойдалана олмайди,LIKE 'matn%'эса фойдаланади.- Устун тури билан қиймат тури мос келмаса, масалан матнли устунни рақам билан солиштирсангиз, MySQL ҳар қаторни ўзгартириб текширишга мажбур бўлиши мумкин.
Индекснинг нархи
Индекс бепул эмас. Ҳар бир қўшимча индекс дискда жой эгаллайди ва жадвалга янги қатор қўшилганда ёки ўзгартирилганда индекс ҳам янгиланиши керак, шунинг учун ёзиш амаллари бироз секинлашади. Кўп ўқиладиган сайтларда бу нарх одатда арзимас, лекин жуда кўп ёзиладиган лог жадвалларида ортиқча индекслар юк бўлиши мумкин. Ишлатилмаётган ва бир-бирини такрорлайдиган индексларни вақти-вақти билан кўриб чиқиб, олиб ташлаш фойдали.
Амалий мисол: етказиб бериш хизмати операторлари
Андижондаги етказиб бериш хизматининг misol.uz сайти ичида операторлар учун бошқарув панели бор эди. Мижоз қўнғироқ қилганда оператор телефон рақами бўйича унинг буюртмаларини қидирарди ва ҳар қидирув тўрт-беш сония давом этарди. Буюртмалар жадвалида бир ярим миллион қатор бор эди, phone устунида эса индекс йўқ эди. Юқоридаги таркибий индекс қўшилгач, EXPLAIN натижасида кўриб чиқиладиган қаторлар сони миллионлардан бир неча ўнтага тушди ва қидирув бир зумда натижа бера бошлади.
Бу ишга сервер созламаларини ўзгартириш ёки кучлироқ тарифга ўтиш керак бўлмади. Shared хостингда ҳам индексни phpMyAdmin орқали ўз базангизда қўшишингиз мумкин, чунки бу фойдаланувчи ҳуқуқлари доирасидаги амал. sayt.uz хостингида қайси сўров секин эканини аниқлашда қийналсангиз, кабинет орқали техник ёрдамга мурожаат қилиш мумкин.