20.10.2026

Kaip rašyti greitesnes ABL užklausas: Progress indeksų parinkimas

Kai tik pradėjau dirbti OpenEdge programuotoju, vienas pirmųjų dalykų, patraukusių mano dėmesį, buvo užklausų našumas. Norėjau suprasti, kas vyksta užkulisiuose, ir netrukus Progress indeksų parinkimas tapo tema, kuri mane domino labiausiai.

Šiame blogo įraše dalinuosi tuo, ką sužinojau testuodamas ABL užklausas: tikrinau, kokie indeksai parenkami, ir matavau, kaip nedideli pakeitimai veikia užklausų našumą.

Kuo labiausiai nustebino indeksų parinkimas?

Progress ABL virtualioji mašina (angl. ABL Virtual Machine, AVM) ne visada pasirenka tą patį indeksą, kurį pasirinktumėte jūs kaip programuotojas. Ji vadovaujasi fiksuotomis parinkimo taisyklėmis ir kartais pasirenka indeksą, kuris verslo požiūriu atrodo mažiau logiškas.

Kas yra duomenų bazės indeksas?

Duomenų bazės indeksas veikia kaip knygos dalykinė rodyklė. Užuot skaitę kiekvieną puslapį, pažiūrite į rodyklę, randate temą ir iškart atsiverčiate puslapius su reikiama informacija.

Lygiai taip pat, kai prašote duomenų bazės konkrečių duomenų, duomenų bazės variklis juos randa naudodamas indeksą. Indeksą sudaro dvi informacijos dalys: indekso raktas ir nuoroda į eilutę (angl. row pointer), rodanti atitinkamą pagrindinės lentelės eilutę.

Paveikslėlyje žemiau tai iliustruojama Sports2020 duomenų bazės lentele Order.

‍

Kodėl Progress indeksų parinkimas svarbus?

Progress AVM laikosi konkrečių indeksų parinkimo ir atmetimo taisyklių. Jos priklauso nuo užklausos, turimų indeksų bei laukų, naudojamų WHERE ar BY sąlygose.

Įprastas procesas atrodo taip:

  • naudotojas pateikia prašymą,
  • programa sugeneruoja duomenų bazės užklausą,
  • Progress AVM įvertina užklausą,
  • AVM parenka vieną ar kelis indeksus,
  • užklausa grąžina prašomus duomenis.

Jei duomenų bazė nuskaito daugiau įrašų nei reikia, užklausa vykdoma ilgiau, o naudotojas ilgiau laukia duomenų.

Todėl programuotojams neužtenka žiūrėti vien į tai, ar užklausa suteikia teisingą rezultatą. Supratę, kaip parenkami indeksai, galite rašyti užklausas, kurios yra ir teisingos, ir efektyvios.

Kaip Progress AVM parenka indeksą?

Pirmiausia AVM atmeta nenaudingus indeksus, o tada iš likusių parenka geriausią pagal atitikties taisykles. Pagrindinės taisyklės pagal prioritetą:

  • iš anksto atrenkami indeksai, kurių pirmieji komponentai naudojami WHERE sąlygoje,
  • jei naudojamas CONTAINS, pasirenkamas žodžių indeksas (angl. word index),
  • pirmenybė teikiama unikaliam indeksui, kurio visi komponentai dalyvauja lygybės atitiktyse (angl. equality matches),
  • pirmenybė teikiama indeksui, turinčiam daugiausia aktyvių lygybės atitikčių,
  • pirmenybė teikiama indeksui, turinčiam daugiausia aktyvių intervalo atitikčių (angl. range matches: >, >=, < bei <=),
  • pirmenybė teikiama indeksui, turinčiam daugiausia aktyvių rūšiavimo atitikčių (angl. sort matches),
  • naudojamas pirminis indeksas,
  • naudojamas pirmasis indeksas pagal pavadinimą abėcėlės tvarka, o laikinosiose lentelėse (angl. temp-tables) – pirmasis apibrėžtas indeksas.

Svarbi detalė – „pilnesnės laukų atitikties“ taisyklė (angl. fuller field match). Indeksas, kurio komponentų atitiktis yra 1/1, laikomas pilnesniu nei indeksas, kurio atitiktis yra 1/2.

Kodėl gali būti pasirinktas kitas indeksas?

Tarkime, OrderLine lentelė turi šiuos indeksus:

‍

Index Fields
itemnum ItemNum
orderline OrderNum, LineNum

‍

Dabar pažvelkite į šią užklausą:

for each Order where Order.Ordernum < 100: 
    for each OrderLine where (OrderLine.Ordernum = Order.Ordernum) 
                       and OrderLine.ItemNum = 3:  

    end. 
end. 

‍

Nežinodamas parinkimo taisyklių, programuotojas gali tikėtis, kad AVM naudos abu indeksus. Arba jis gali manyti, kad laimės „akivaizdžiai logiškas“ orderline indeksas, nes užklausa filtruoja pagal OrderNum. Tačiau AVM pasirenka tik vieną indeksą – itemnum, kuris nuskaito gerokai daugiau įrašų.

Kodėl? Nes itemnum indekso atitiktis yra pilna, 1/1, o orderline – tik 1/2.

Kokius įrankius galima naudoti?

Nespėliokite, kuris indeksas naudojamas – patikrinkite tai įrankiais. XREF, LOG-MANAGER bei PROMON padeda tirti užklausų elgseną skirtingais aspektais. Kiekvienas įrankis turi savo paskirtį:

Tool Main Use
XREF Checks index usage early, before runtime
LOG-MANAGER Helps trace which code is running during execution
PROMON Shows database activity, especially reads

‍

Pavyzdžio testavimas su XREF ir PROMON

Ankstesniame pavyzdyje XREF patvirtino, kuris indeksas buvo naudojamas:

1 COMPILE custom.p 

1 CPINTERNAL ISO8859-1 

1 CPSTREAM ISO8859-1 

17 BLOCK-LEVEL ON ERROR UNDO, THROW 

18 STRING "iCounter" 8 NONE UNTRANSLATABLE 

21 STRING "Order" 5 NONE UNTRANSLATABLE 

21 ACCESS sports2000.Order Ordernum 

21 SEARCH sports2000.Order OrderNum 

22 STRING "OrderLine" 9 NONE UNTRANSLATABLE 

22 ACCESS sports2000.OrderLine Ordernum 

22 ACCESS sports2000.Order Ordernum 

22 ACCESS sports2000.OrderLine Itemnum 

22 SEARCH sports2000.OrderLine itemnum 

‍

Tada PROMON parodė, kiek įrašų buvo nuskaityta:

Event Total Per Sec
Undos 0 0.0
Record Reads 26294 3756.3
Record Deletes 0 0.0
DB Reads 0 0.0
BI Reads 0 0.0
Record Waits 0 0.0
Buffs Flushed 0 0.0

‍

Užklausa atliko 26 294 nuskaitymus iš duomenų bazės.

Norėdamas sumažinti nuskaitymų skaičių, į WHERE sąlygą pridėjau AND OrderLine.LineNum > 0:

for each Order where Order.Ordernum < 100: 
    for each OrderLine where (OrderLine.Ordernum = Order.Ordernum and OrderLine.LineNum > 0) 
                       and OrderLine.ItemNum = 3: 

    end. 
end. 

‍

Įrašų nuskaitymų skaičius sumažėjo iki 864, o parinktas indeksas pasikeitė į orderline. Tai patvirtino ir PROMON, ir XREF:

Event Total Per Sec
Undos 0 0.0
Record Reads 864 54.0
Record Deletes 0 0.0
DB Reads 0 0.0
BI Reads 0 0.0
Record Waits 0 0.0
Buffs Flushed 0 0.0

‍

1 COMPILE custom.p 

1 CPINTERNAL ISO8859-1 

1 CPSTREAM ISO8859-1 

17 BLOCK-LEVEL ON ERROR UNDO, THROW 

18 STRING "iCounter" 8 NONE UNTRANSLATABLE 

21 STRING "Order" 5 NONE UNTRANSLATABLE 

21 ACCESS sports2000.Order Ordernum 

21 SEARCH sports2000.Order OrderNum 

22 STRING "OrderLine" 9 NONE UNTRANSLATABLE 

22 ACCESS sports2000.OrderLine Ordernum 

22 ACCESS sports2000.Order Ordernum 

22 ACCESS sports2000.OrderLine Itemnum 

22 ACCESS sports2000.OrderLine Linenum 

22 SEARCH sports2000.OrderLine orderline 

‍

Tačiau šis pakeitimas atnešė naują riziką.

Kodėl „gudri“ WHERE sąlyga yra rizikinga?

Sports2020 duomenų bazėje OrderLine įrašų LineNum reikšmės prasideda nuo 1, todėl „gudri“ užklausa problemų nesukėlė.

Vis dėlto, jei duomenų bazėje nėra apribojimo, neleidžiančio LineNum būti 0 ar neigiamam, užklausa gali nepastebimai grąžinti neteisingus rezultatus.

Dėl to kyla trys problemos:

  • Duomenų netikslumo rizika. Užklausa remiasi prielaida, kurios duomenų bazė gali neužtikrinti. ‍
  • Sudėtingesnė priežiūra. Ateityje kiti programuotojai gali nesuprasti, kodėl buvo pridėta AND LineNum > 0. ‍
  • Paslėpti našumo kompromisai. Užklausa gali sumažinti įrašų nuskaitymų skaičių, tačiau kai kuriais atvejais padidinti indekso blokų nuskaitymų skaičių.

Ar programuotojams verta naudoti USE-INDEX?

Programuotojams nereikėtų naudoti USE-INDEX kaip numatytojo sprendimo. Jis gali padėti, bet tik tada, kai suprantate, kodėl AVM pasirinko kitą indeksą ir kodėl priverstinai nurodytas indeksas yra geresnis.

USE-INDEX turi ir trūkumų:

  • apeina įprastą AVM indeksų parinkimo logiką,
  • gali pasenti, jei pasikeičia duomenų bazės schema,
  • gali paslėpti gilesnes projektavimo problemas,
  • gali sumažinti kodo lankstumą.

Vis dėlto kai kuriais atvejais USE-INDEX yra geriausias pasirinkimas. Mano pavyzdyje USE-INDEX orderline tinka geriau nei „gudri“ WHERE sąlyga. Taip naudojamas tas pats efektyvus indeksas, bet nereikia remtis prielaida apie LineNum reikšmes.

Pagrindinė taisyklė paprasta: USE-INDEX naudokite tik tada, kai išmatavote užklausą, patikrinote alternatyvas bei supratote poveikį.

Koks geriausias būdas optimizuoti ABL užklausas?

Geriausias būdas optimizuoti ABL užklausas – derinti indeksų parinkimo žinias su matavimais. Supraskite taisykles, peržiūrėkite parinktus indeksus, matuokite duomenų bazės nuskaitymus bei patikrinkite kiekvieną pakeitimą.

Praktikoje tai tas pats ciklas, kurį taikiau šiame įraše: parašykite užklausą, XREF įrankiu patvirtinkite indeksą, PROMON įrankiu išmatuokite nuskaitymus, pakoreguokite ir testuokite iš naujo.

Svarbiausios įžvalgos apie ABL užklausų našumą

Geras užklausų našumas – tai ne tik teisingai parašyta WHERE sąlyga. Svarbu ir suprasti, kaip ją interpretuoja Progress AVM. Mano testuose vienas indekso parinkimo skirtumas sumažino nuskaitymų skaičių nuo 26 294 iki 864. Jei programa tą užklausą vykdo šimtus kartų per dieną, skirtumas tarp šių dviejų skaičių lemia, ar ekranas įsikels per sekundę, ar naudotojas pagalvos, kad sistema sugedo.

Svarbiausios šio testo pamokos:

  • Progress AVM indeksus parenka pagal fiksuotas taisykles, o ne pagal verslo logiką. Pilnesnė atitiktis (1/1) laimi prieš dalinę (1/2), net jei nuskaito gerokai daugiau įrašų.
  • Niekada nespėliokite, kuris indeksas naudojamas. Prieš kiekvieną pakeitimą ir po jo patvirtinkite indeksą su XREF ir išmatuokite nuskaitymus su PROMON.
  • „Gudri“ WHERE sąlyga gali pakeisti parenkamą indeksą, tačiau gali ir grąžinti neteisingus rezultatus, jei duomenų prielaida nėra užtikrinta. ‍
  • USE-INDEX – sąmoningai naudojamas įrankis išmatuotiems atvejams, o ne numatytasis sprendimas.

Progress indeksų parinkimą galima numatyti, kai žinote taisykles, net jei jis ne visada intuityvus. XREF ir PROMON patikras įtraukite į kasdienį kūrimo ir kodo peržiūros procesą. Rinkitės pataisymus, po kurių užklausos išlieka teisingos ir lengvai skaitomos. Taip lėtas užklausas pastebėsite gerokai anksčiau nei jūsų naudotojai.

Jei jūsų organizacija nori pagerinti ABL programų našumą ar išplėsti Progress OpenEdge sistemas, apsilankykite Progress OpenEdge produkto puslapyje ir sužinokite daugiau apie šią platformą bei platesnę jos ekosistemą.

No items found.

Susiję straipsniai

Pasikalbėkime apie jūsų projektą

Pradedate projektą arba norite sustiprinti jau vykdomą? Susisiekite ir atsakysime jums per vieną darbo dieną.

Parašykite mums

Ačiū! Jūsų pateikimas gautas!
Oi! Pateikiant formą kažkas nutiko.