Problema
Veikimo derinimas ir kliūčių analizė „Progress“ programose gana skiriasi nuo to, prie ko esame įpratę daugelyje kitų aplinkų. Kartais atrodo, kad indekso pasirinkimas OpenEdge aplinkoje ne visada vyksta pagal tikėtinas taisykles. Žinoma, už to slypi logika, tačiau realiuose projektuose atsakymas ne visada akivaizdus. Labai dažnai veikimo problemų sprendimas reikalauja programuotojo nuojautos, patirties ir gero supratimo, kaip suprojektuota duomenų bazė, derinio.
Vienas iš esminių skirtumų – OpenEdge duomenų bazė nepateikia tokio paties tipo lentelių statistikos, kokią pateikia daugelis kitų duomenų bazių. Neseniai dirbau su atveju, kuriame tokia informacija būtų buvusi labai naudinga.
Daugeliu atvejų Profiler arba xRef sąrašo (listing) pakanka veikimo problemoms rasti ir išspręsti. Beveik visada.
Šiuo atveju turėjau labai paprastą lentelę, naudojamą importuotiems įrašams saugoti. Svarbiausi laukai buvo:

BatchId, ImportOrder ir State. Įrašai buvo importuojami partijomis (batch), ir kiekvienas tos pačios partijos įrašas turi tą patį BatchId. Kiekvienas partijos įrašas gavo savo importavimo eilės numerį kaip ImportOrder. State žymi kiekvieno įrašo statusą: IMPORTED, OK, ERROR ir t.t. Lentelė, be kitų, turėjo kombinuotą indeksą idx_BatchId_ImportOrder ir vieno lauko indeksą idx_State.

Norėjau pateikti ataskaitą apie šiuo metu importuojamos partijos įrašus, kurie nepavyko ir gavo ERROR statusą. Užklausa buvo paprasta:
Tikėjausi, kad „Progress“ naudos idx_BatchId_ImportOrder indeksą, arba galbūt sujungs indeksus, apimančius užklausoje naudojamus laukus.
Taip neatsitiko. „Progress“ naudojo idx_State, ir užklausa vyko itin lėtai. Sąlygų tvarkos keitimas užklausoje nepadėjo.
Veikimo testas
Norėdamas patvirtinti veikimo poveikį, paruošiau testą bandomojoje aplinkoje. Lentelėje buvo 1 000 000 įrašų. Paleidau užklausą 100 kartų, kiekvieną kartą nurodydamas skirtingą BatchId. Kiekviena užklausa grąžindavo apie 900 įrašų.
Palyginau originalią užklausą su versija, kurioje indeksas buvo aiškiai priverstas naudoti:

Vidutinis vienos užklausos vykdymo laikas buvo:
- su numatytuoju indeksu – apie 950 milisekundžių;
- su priverstinai nustatytu (
USE-INDEX) indeksu – apie 2 milisekundes.
Tai milžiniškas skirtumas. Taigi, taip, tikrai verta ieškoti tokių atvejų.
Kodėl Progress OpenEdge pasirinko šį indeksą
Pirma mintis būtų, kad Progress turėtų naudoti du indeksus šiai užklausai. Tačiau tai įmanoma tik tada, kai visi kiekvieno indekso komponentai naudojami lygybės sąlygose (angl. equality match).
Šiuo atveju laukas ImportOrder nebuvo naudojamas užklausoje, todėl „Progress“ negalėjo naudoti kombinuoto indekso taip, kaip tikėjausi.
Panaši priežastis sutrukdė ir idx_BatchId_ImportOrder indeksui būti pasirinktam kaip pagrindiniam.
Bendrosios taisyklės indekso pasirinkimui yra šios:
- Naudoti indeksą, nurodytą
USE-INDEXparinktyje. - Jei yra
CONTAINSsąlyga, naudoti žodžių indeksą. - Jei indeksas yra unikalus ir visi jo komponentai naudojami aktyviose lygybės sąlygose, naudoti unikalų indeksą.
- Naudoti indeksą su daugiausiai aktyvių lygybės sąlygų atitikmenų.
- Naudoti indeksą su daugiausiai aktyvių intervalo (range) atitikmenų.
- Naudoti indeksą su daugiausiai rikiavimo atitikmenų.
- Esant lygiosioms, naudoti indeksą, kuris pirmas pagal abėcėlę. Jei tarp lygiųjų yra
PRIMARYindeksas, naudotiPRIMARYindeksą. - Naudoti pirminį (primary) indeksą.
Svarbiausia šiuo atveju yra taisyklė Nr. 4.
idx_BatchId_ImportOrder indeksas nebuvo pasirinktas, nes užklausoje buvo naudojamas tik pirmasis kombinuoto indekso laukas. Antrasis laukas, ImportOrder, nebuvo naudojamas.
Tuo tarpu idx_State indeksas turėjo vieną lauką, ir tas laukas buvo naudojamas užklausoje. „Progress“ požiūriu tai atrodė kaip geresnis atitikmuo.
Techniškai Progress pasirinko indeksą. Tačiau duomenų selektyvumo (angl. selectivity) požiūriu tai buvo blogas pasirinkimas. Mano duomenyse buvo tūkstančiai įrašų su State = "ERROR" iš daugelio importavimo sesijų, tačiau tik keli šimtai įrašų su tuo pačiu BatchId.
Taigi, užklausa nuskaitė žymiai daugiau duomenų, nei buvo būtina.
Geresnio aptikimo būdo paieška
Naudoju Matt Verrinder nemokamą xRefAnalyzer įrankį, kuris man daug kartų padėjo. Taip pat esu padaręs keletą nedidelių jo patobulinimų.
Tačiau šiuo atveju jis nepateikė aiškaus įspėjimo.
Įrankis paryškina užklausas raudonai, kai naudojamas WHOLE-INDEX. Tačiau šiuo atveju „Progress“ tikrai pasirinko indeksą. Jis tiesiog nepasirinko geriausio duomenims tinkančio varianto. Todėl akivaizdaus signalo nebuvo.
Turėjau tūkstančius įrašų su ERROR statusu iš daugelio importavimo sesijų ir tik keletą šimtų įrašų vienam BatchId. Vis tiek man teko kelis kartus peržiūrėti užklausą, kol pastebėjau, kad pasirinktas indeksas buvo tikroji prasto veikimo priežastis.

Ši reikšmė atspindi santykį tarp skirtingų reikšmių lauke ir bendro įrašų skaičiaus lentelėje. Jei reikšmė artima 1, beveik kiekvienas įrašas turi skirtingą reikšmę tame lauke. Tai reiškia, kad laukas turi labai aukštą selektyvumą.
Kuo mažesnė reikšmė, tuo daugiau įrašų turi tą pačią lauko reikšmę. Dėl to indeksas tampa mažiau selektyvus, ir užklausai gali tekti nuskaityti daugiau įrašų.
Apskritai indeksai laukuose su didesniu selektyvumu paprastai veikia efektyviau.
Turėdamas selektyvumo informaciją, kitas žingsnis buvo akivaizdus. Kodėl gi nesujungus jos su xRef duomenimis Matt Verrinder įrankyje?
Išplėčiau xRefAnalyzer taip, kad jis vis dar įspėtų apie WHOLE-INDEX naudojimą, bet taip pat nurodytų užklausas, kuriose gali egzistuoti potencialiai geresnis indeksas. Kiekvienam galimam indeksui įrankis parodo selektyvumo balą, padedantį nuspręsti, ar „Progress“ pasirinktas indeksas iš tikrųjų yra geriausias variantas.

Kombinuotiems indeksams lauko selektyvumą sumuoju tik tada, kai indeksuoti laukai eina iš eilės ta pačia tvarka, kaip indekse, ir taip pat naudojami užklausoje.
Galimi patobulinimai
Vis dar yra ką tobulinti.
Šiuo metu mano duomenų analizatorius kiekvieną kartą skaičiuoja rezultatus skirtingai lentelei. Ateityje jį būtų galima pritaikyti veikti partijų (batch) režimu ir paleisti mažiau apkrautomis valandomis. Taip pat būtų galima pridėti laiko žymą, žyminčią, kada apskaičiuoti rezultatai pasensta.
Kitas naudingas patobulinimas būtų laiko limitas, sustabdantis analizę po nustatyto laikotarpio, pavyzdžiui, po dviejų valandų. Tai padarytų įrankį saugesnį naudoti didesnėse duomenų bazėse.
Visada yra ką patobulinti.
Rezultatai ir pagrindinės įžvalgos
Apibendrinant, visada patikrinkite, kurį indeksą Progress pasirinko jūsų užklausai. Pagalvokite apie duomenis, su kuriais dirbate. Laukas gali būti indeksuotas ir vis tiek būti prastas pasirinkimas, jei jame yra tik kelios skirtingos reikšmės.
Taip pat, projektuojant duomenų bazių struktūras, atminkite, kad daugiakomponenčiai (angl. multi-field) indeksai yra galingi, bet ne visada turi pirmenybę prieš vieno lauko indeksus. „Progress“ indekso pasirinkimas labai priklauso nuo to, kiek pirmaujančių indekso komponentų naudoja užklausa.
Auksinė taisyklė paprasta: indeksas naudingas tik tada, kai jūsų užklausa gali jį efektyviai panaudoti.
Rašykite kokybišką kodą, testuokite savo produktą ir niekada nelaikykite savaime suprantamu dalyku, kad pasirinktas indeksas yra geriausias.
Jei susiduriate su lėtomis „Progress OpenEdge“ užklausomis, netikėtu indekso pasirinkimu ar sunkiai paaiškinamomis veikimo problemomis, galime padėti. Susisiekite su mūsų komanda.
Dažniausiai užduodami klausimai
Kodėl Progress kartais pasirenka netinkamiausią indeksą?
„Progress“ indekso pasirinkimo taisyklės remiasi tuo, kiek pirmaujančių indekso komponentų naudoja užklausa lygybės sąlygose, o ne duomenų selektyvumu. Todėl vieno lauko indeksas su mažu selektyvumu gali būti pasirinktas vietoj kombinuoto indekso, jei užklausa nenaudoja visų jo komponentų.
Kas yra selektyvumas (selectivity) duomenų bazės kontekste?
Selektyvumas – tai santykis tarp skirtingų reikšmių lauke ir bendro įrašų skaičiaus lentelėje. Kuo reikšmė artimesnė 1, tuo daugiau unikalių reikšmių laukas turi, ir tuo efektyvesnis tampa jo indeksas.
Kaip xRefAnalyzer įrankis padeda aptikti tokias problemas?
xRefAnalyzer įspėja apie WHOLE-INDEX naudojimą ir, su autoriaus pridėtais patobulinimais, taip pat parodo selektyvumo balą galimiems indeksams – tai padeda nustatyti atvejus, kai Progress pasirinktas indeksas techniškai galioja, bet nėra geriausias duomenims.
Ką daryti, jei užklausa veikia lėtai, nors indeksai egzistuoja?
Verta patikrinti, kurį indeksą Progress iš tikrųjų naudoja, ir palyginti jį su duomenų selektyvumu. Jei reikia, indeksą galima priverstinai nurodyti naudojant USE-INDEX parinktį ir patikrinti veikimo skirtumą.

