Оптимизација упита () је компонента процесора упитног језика која је неопходна, бар код великих система и за велике базе података, да би систем уопште могао да задовољи тражену ефикасност. Оптимизатор упита покушава да одреди најефикаснији начин да се изврши дати упит разматрањем могућих планова упита. Посебну погодност код оптимизација упита пружају релациони системи, с обзиром на довољно апстрактни ниво релационих израза којима се упити задају. Обично сам корисник не може да приступи директно самом оптимизатору упита јер се он одвија аутоматски унутар система за управљање базама података, међутим, постоје базе података које дозвољавају вођење оптимизатора упита и то су нерелациони системи.
Упит () је захтев за информацијама из базе података. Резултати упита се генеришу приступањем и манипулацијом релевантних података унутар базе података у зависности од тражене информације. Пошто је структура база података комплексна, у већини случајева, упити су комлексни и понекад захтев за подацима из упита могу бити прикупљани од стане различитих база података којима се приступа на различите начине. Сваки другачији начин приступа бази података захтева различито време обраде. Па тако, време обраде може варирати од једног делића секунде до више сати, зависно од изабраног начина приступа бази података. Сврха оптимизације упита, који је аутоматизован процес, јесте да се пронађе начин да се дати упит обради у минималном времену. Проналажење тачног оптималног пута за извршавање упита, међу свим могућим, је веома сложен, дуготрајан процес, који може пуно да кошта по цени времена а често и не може да се пронађе. Тако оптимизација упита обично покушава проналазак оптималног пута упоређивањем неколико разумних алтернатива које се одвијају у разумном року и да тако пронађе "довољно добар" план који обично много не одступа од најбољег могућег резултата.
Историја Историја оптимизације упита почиње настанком првих упитних језика, па је тако развијањем база података и упитних језика за те базе података, развијана и оптимизација упита.
Узроци лоших перформанси упита Ситуације које лоше утичу на перформансе SQL () упита а самим ти и саме апликације могу бити различите, а неке од њих су: лоше индексирање, нетачна статистика, превише међусобних блокирања трансакција и застоја, операције које нису засноване на раду са скуповима података, лоша спецификација упита, лоша организација базе података, план избршења упита који се не кешира, честа рекомпилација плана извршења, неправилна употреба курсора.
Лоше индексирање Лоше индексирање може драстично да утиче на време избршавања упита, јер се приликом избршења упита приступа већој количини података што директно доводи до повећања приступа диску, коришћења меморије и порецесора, а што директно утиче на повећање времена избршења упита. Нетачна статистика Нетачна статистика може значајно да наруши перформансе упита. Оптимизатор упита у оквиру система за управљање базама података, на основу нетачне статистике о дистрибуцији података, може да доносе погрешну процену о нпр. броју записа које упит треба да врати, а који је важан параметар оптимизатору за дефинисање оптималног и ефикасног плана избршења упита. Превише међусобног блокирања трансакција и застоја Превише међусобног блокирања трансакција и застоја доводи до значајног нарушавања перформанси упита. Уколико две трансакције приступају истом податку у табели са конфликтом, долази до узајмног блокирања једне од трансакција и на тај начин до чекања или враћења блокиране трансакције на поновно избршење. Блокирање је нормална појава, али превише блокирања може значајно да наруши перформансе. Застој се дешава када две трансакције истовремено блокирају једна другу. Системи за управљање базама података периодично трагају за застојима и једну од трансакција жртвују и браћају је на почетак извршавања. Операције које нису засноване на раду са скуповима података Операције које нису засноване на раду са скуповима података него се заснивају на обради података употребом курсора и петљи, значајно могу да наруше перформансе упита. Лоша спецификација упита Лоша спецификација упита је најчешће разлог лоших перформанси упита, јер се жељени резултат може добити дефинисањем упита на више различитих начина, а неки од тих начина онемогућују оптимизатор да употреби адекватан индекс и смањи време извршавања упита. Лоша организација базе података Лоша организација базе података, односно недовољна или прекомерна нормализација базе података, може негативно да утиче на време избршавања упита због непотребног повећања обима података које упит обрађује и повећања броја блокирања упита или повећања броја операција спајања (). План извршења упита који се не кешира План извршења упита који се не кешира нарушава перформансе упита, јер оптимизатор упита система за управљање базама података троши одређено време за креирање плана извршења упита и продужава укупно време извршавања упита. Честа рекомпилација плана извршења Честа рекомпилација плана извршења повећава време извршења упита, јер се троши одређено време за рекомпилацију плана извршења. За избегавање рекомпилације, план извршења упита мора бири независан од параметра који се прослеђују упиту приликом извршења, а то се најчешће постиже употребом ускладиштених процедура. Неправилна употреба курсора Неправилна употреба курсора повећава време извршавања упита. Употребом курсора у оквиру упита подаци из табеле се добављају ред по ред, а системи за управљање базама података су оптимизовани за читање и обраду читавих скупова редова. Уколико се курсори ипак морају користити, онда треба водити рачуна о томе да постоје различите врсте курсора које различито утичу на повећање времена извршавања упита.
Имплементација оптимизације упита у SQL Упит се често може написати на два или више начина, а да се при томе добије исти резултат након његовог извршења. Упити написани на различите начине обично дају различите планове извршења упита, које на основу написаног упита креира оптимизатор упита у оквиру система за управљање базама података. Различити планови извршења упита дају различита времена извршења упита, па стога постоје планови који су бољи од других планова. Приликом писања упита, уколико је могуће, увек треба дефинисати упит на начин да се добије добар (или оптималан) план извршења, а тиме и мање време извршења упита. Две основне врсте оптимизације које се срећу у процесорима упитних језика јесу стратегија алгебарских трансформација упита и статегија процене цена. Прва не зависи од специфичних података у бази, док друга зависи. Тако би, на пример, једно правило алгебарске трансформације, које је скоро увек добро применити, било: применити рестрикцију што је пре могуће раније у извршавању упита. Стратегије процене цене користе информацију (из системског каталога) о постојању индекса над табелом из упита. Са циљем постизања најбољих перформанси упита пожељно је придржавати се следећих препорука: рад са малим скуповима података ефективна употреба индекса избегавати давање упута оптимизатору користити доменски и референцијални интегритет избјегавати упите који интензивно користе ресурсе смањити комуникацију преко мреже смањити трајање трансакција Међутим, наведене препоруке различито утичу на побољшање перформанси упита у различитим реалним окружењима, па је најбоље извршити тестирања различитих форми истог упита у реалном окружењу и на основу добијених резултата извршити оптимизацију упита.
Рад са малим скуповима података Смањењем и ограничењем скупа података (колона и редова) над којима се извршава упит смањује се употреба ресурса и повећава ефикасност индекса, што позитивно утиче на перформансе упита. Један од начина за смањење скупа података у упиту је да се листа колона у оквиру SELECT листе упита ограничи само на колоне које су неопходне, односно да се избјегава упит типа SELECT *. Други начин за смањење скупа података у упиту је да се употребом WHERE клаузуле смањује број редова уколико је то могуће, јер се на тај начин оптимизација упита реализује ефикаснијом употребом индекса. Уколико се као резултат упита кориснику треба презентовати велика количина података, онда се може, уколико је прихватљиво, извршити страничење података (енг. paging), односно на захтјев корисника слати један по један скуп записа.
Ефективна употреба индекса Познато је да индекси (clustered index – подаци су смештени на диску редоследом како су сортирани и non-clustered indexes – сортирани су само индекси на податке који се налазе разбацани на диску) дефинисани над одговарајућим колонама (најчешће кориштеним у упитима) убрзавају извршење упита. Међутим, подједнако је важно да ови индекси буду ефикасно искориштени приликом дефинисања упита. Ефикасна употреба индекса над колоном која се налази у оквиру where клаузуле упита зависи од израза, односно операција које се врше над том колоном у оквиру wхере клаузуле (брза Index Seek операција извршава се уколико се ради о високо селективном упиту, односно уколико се за добијање резултата упита мора обрадити мали број редова, 10-15% редова од укупног броја редова у табели). На примјер, оператор „!=“ захтијева скенирање читаве табеле иако је над колоном дефинисан индекс, што представља неефикасну употребу индекса (спорија Index Scan операција). Непожељни оператори, које треба избјегавати над колонама са индексом у оквиру WHERE клаузуле, су оператори искључења (<>, !=, !>, !<, NOT EXISTS, NOT IN и NOT LIKE IN, OR), а некада и оператор LIKE (LIKE '%tekst'). Наравно, не могу се увек избећи ови оператори, али када је могуће предефинисати упит тако да враћа исти резултат кориштењем других оператора, онда то треба размотрити у циљу побољшања перформанси упита. Неоптимизовани LIKE упит:
SELECT zaposleni.ime FROM zaposleni WHERE zaposleni.ime LIKE 'Dej%'SQL code , приступано 18.01.2014., 19.01.2014.
Оптимизован LIKE упит:
SELECT zaposleni.ime FROM zaposleni WHERE zaposleni.ime >= 'Dej' AND zaposleni.ime < 'DeK' Врло често оптимизатор система за управљање базама података, уколико је то могуће, изврши конверзију упита у оптимизовани облик тако што конвертује непожељни израз у одговарајући пожељни израз (нпр. !< замјени са >=). Да би се постигла ефикаснија употреба индекса, потребно је избегавати аритметичке операције над колонама у оквиру where клаузуле: Неоптимизовани упит:
SELECT zaposleni.ime, zaposleni.pozicija FROM zaposleni WHERE zaposleni.godina * 2 > 60
Оптимизован упит:
SELECT zaposleni.ime, zaposleni.pozicija FROM zaposleni WHERE zaposleni.godine > 60/2 Избјегавати функције над колонама у оквиру WHERE клаузуле, нпр: Неоптимизовани упит:
SELECT zaposleni.ime FROM zaposleni WHERE SUBSTRING(zaposleni.ime,1,1) = 'D'
Оптимизован упит:
SELECT zaposleni.ime FROM zaposleni WHERE zaposleni.ime>='F' AND zaposleni.ime<'G'
Избегавати давање упута оптимизатору Избегавати давање упута оптимизатору. Давањем упута оптимизатору се онемогућава да оптимизатор динамички дефинише план извршења упита у време његовог планирања и реализације. На овај начин се обично нарушавају перформансе упита, па треба избегавати JOIN упуте (енг. join hints), INDEX упуте (енг. index hints) и FORCEPLAN упуте (енг. forceplan hints) приликом дефинисања упита.
Користити доменски и референцијални интегритет Доменски интегритет представља ограничење скупа вредности које неки атрибут скупа ентитета (нека колона у табели) може да садржи, а референцијални интегритет је ограничење да се нека вредност која се појављује у једној релацији мора налазити и у другој релацији. Доменски и референцијални интегритет омогућавају оптимизатору да провери валидност података без физичког приступа подацима. Смањивање броја физичких приступа подацима, позитивно утиче на перформансе упита, смањујући време извршења упита. Пример утицаја доменског интегритета на перформансе упита је NOT NULL ограничење (дефинисање да колона мора садржати неку вредност). Упит дефинисан на следећи начин SELECT zaposleni.ime, zaposleni.godine FROM zaposleni