13.11.2025
Antanas Valencius

Buffer handles: greitesnis duomenų eksportas OpenEdge 12.8

Nepriklausomai nuo to, kokią Progress OpenEdge programą kuriate, anksčiau ar vėliau jums prireiks perkelti duomenis – ar tai būtų atsarginė kopija, migracija, ar integracija su kita sistema. Iki šiol programuotojai turėdavo pasikliauti įrankiais (utilities), temp-tables struktūromis arba pasirinktiniais ABL skriptais. Šie metodai veikė, tačiau kiekvienas turėjo kompromisų lankstumo, veikimo ar priežiūros atžvilgiu.

Su OpenEdge 12.8 versija tai keičiasi. Nauji buffer handles eksportui ir importui daro darbą su duomenimis švaresnį, greitesnį ir žymiai lengviau valdomą.

Esu „Progress“ programuotojas „Baltic Amadeus“ komandoje, ir šiame blogo įraše apžvelgsime, kaip duomenų eksportas ir importas veikė prieš 12.8 versiją, kas naujo su buffer handles, ir kaip jie gali padaryti jūsų darbo procesus paprastesnius bei greitesnius.

Prieš Progress OpenEdge 12.8: tradiciniai duomenų perkėlimo būdai

Prieš Progress OpenEdge 12.8 versiją programuotojai turėjo kelis nusistovėjusius duomenų eksportavimo ir importavimo metodus. Pažvelkime į juos atidžiau.

1 variantas: įrankių (utilities) naudojimas (.d failai)

Vienas seniausių ir patikimiausių metodų – naudoti integruotus Progress OpenEdge įrankius:

proutil mydb -C dump sports.customer customer.d

proutil mydb -C load sports.customer customer.d  

Šios komandos yra greitos, paprastos ir patikimos, todėl puikiai tinka pilno lentelės eksportui. Tačiau jos nėra labai lanksčios: negalite filtruoti įrašų, pasirinkti konkrečių laukų ar keisti formato. Arba eksportuojate viską, arba nieko.

Data Administration įrankis viduje naudoja būtent šiuos pačius utilities.

2 variantas: temp-tables naudojimas (JSON/XML)

Temp-tables yra dar vienas populiarus būdas eksportuoti ir importuoti duomenis OpenEdge aplinkoje. Jie lankstūs, lengvai suprantami ir gerai veikia su JSON ar XML formatais.

Štai paprastas pavyzdys:

// Export 
define temp-table ttCustomer no-undo like Customer.  
for each Customer no-lock: 
create ttCustomer. 
    buffer-copy Customer to ttCustomer. 
end.  
temp-table ttCustomer:write-json("file", "Customer.json", true). 
// or 
temp-table ttCustomer:write-xml("file", "Customer.xml", true). 

// Import 
define temp-table ttCustomer no-undo like Customer.  
temp-table ttCustomer:read-json("file", "customer.json"). 
// or 
temp-table ttCustomer:read-xml("file", "customer.xml", "empty", ?, ?, ?). 

for each ttCustomer: 
create Customer. 
buffer-copy ttCustomer to Customer. 
end.  

Kartais reikia kažko dinamiškesnio, pavyzdžiui, eksportuoti visas duomenų bazės lenteles be poreikio žodynu (hardcode) nurodyti kiekvieną atskirai. Tai galima padaryti skaitant lentelių metaduomenis iš schemos lentelių _File ir _Field. Procesas atrodo taip:

VAR HANDLE hTable.  
FOR EACH _File NO-LOCK WHERE 
          _File._Tbl-Type EQ "T": 
    CREATE TEMP-TABLE hTable. 
    FOR EACH _Field NO-LOCK WHERE 
             _Field._File-recid EQ RECID(_File): 
        hTable:ADD-NEW-FIELD(_Field._Field-Name, _Field._Data-Type). 
    END. 
    hTable:TEMP-TABLE-PREPARE("tt" + _File._File-Name). 
END.  

Po to lieka tik užklausti duomenų iš duomenų bazės, užpildyti temp-table ir eksportuoti pasirinktu formatu, pavyzdžiui, JSON:

CREATE BUFFER hBuffer FOR TABLE _File._File-Name. 
CREATE BUFFER hTTBuffer FOR TABLE hTable. 

CREATE QUERY hQuery. 
hQuery:SET-BUFFERS(hBuffer). 
hQuery:QUERY-PREPARE("for each " + hBuffer:NAME). 
hQuery:QUERY-OPEN(). 
hQuery:GET-FIRST().  

// Query the DB and copy the buffer to dynamic Temp-Table 
DO WHILE NOT hQuery:QUERY-OFF-END: 
  hTTBuffer:BUFFER-CREATE(). 
  hTTBuffer:BUFFER-COPY(hBuffer). 
  hQuery:GET-NEXT(). 
END.  

// Export the data 
hTable:WRITE-JSON("file", "./export/" + _File._File-Name + ".json", TRUE).  

Jei norite dinamiškai eksportuoti kiekvieną lentelę, štai pilnas kodas:

VAR HANDLE hTable. 
VAR HANDLE hBuffer. 
VAR HANDLE hTTBuffer. 
VAR HANDLE hQuery.  

FOR EACH _File NO-LOCK WHERE 
          _File._Tbl-Type  = "T": 
    CREATE TEMP-TABLE hTable. 
        FOR EACH _Field NO-LOCK WHERE 
             _Field._File-recid EQ RECID(_File): 
        hTable:ADD-NEW-FIELD(_Field._Field-Name, _Field._Data-Type). 
    END. 
    hTable:TEMP-TABLE-PREPARE("tt" + _File._File-Name). 

    CREATE BUFFER hBuffer FOR TABLE _File._File-Name. 
    CREATE BUFFER hTTBuffer FOR TABLE hTable. 

    CREATE QUERY hQuery. 
    hQuery:SET-BUFFERS(hBuffer). 
    hQuery:QUERY-PREPARE("for each " + hBuffer:NAME). 
    hQuery:QUERY-OPEN(). 
    hQuery:GET-FIRST(). 

    DO WHILE NOT hQuery:QUERY-OFF-END: 
        hTTBuffer:BUFFER-CREATE(). 
        hTTBuffer:BUFFER-COPY(hBuffer). 
        hQuery:GET-NEXT(). 
    END. 

    hQuery:QUERY-CLOSE(). 

    hTable:WRITE-JSON("file", "./export/" + _File._File-Name + ".json", TRUE). 

    DELETE OBJECT hQuery. 
    DELETE OBJECT hTTBuffer. 
    DELETE OBJECT hTable. 
    DELETE OBJECT hBuffer. 
END.  

Šis būdas yra aiškus ir patogus programuotojui. Jis leidžia dinamiškai eksportuoti kiekvieną duomenų bazės lentelę kaip JSON failus, nerašant atskiros logikos kiekvienai lentelei.

Trūkumas tas, kad temp-tables saugo viską operatyviojoje atmintyje. Mažesniems duomenų rinkiniams tai nėra problema, tačiau didesniems prireiks partijavimo (batching), o tai prideda sudėtingumo.

3 variantas: ABL Export/Import naudojimas

Kitas variantas – integruoti EXPORT ir IMPORT sakiniai. Šis būdas puikiai tinka, kai norite visą procesą valdyti kode:

// Export 
OUTPUT TO VALUE("customers.d"). 
FOR EACH Customer NO-LOCK: 
    EXPORT DELIMITER "," Customer.CustNum Customer.Name Customer.SalesRep. 
END. 
OUTPUT CLOSE. 

// Import 
INPUT FROM VALUE("customers.d"). 
REPEAT ON ENDKEY UNDO, LEAVE: 
    CREATE Customer. 
    IMPORT DELIMITER "," Customer.CustNum Customer.Name Customer.SalesRep. 
END. 
INPUT CLOSE.  

Logika čia paprasta: paleidžiama užklausa, tuomet naudojama EXPORT rašymui arba IMPORT skaitymui. Tai suteikia daugiau kontrolės formatavimui, nes galite pasirinkti skirtukus (delimiters) ir tiksliai nurodyti, kuriuos laukus įtraukti.

Tačiau norint padaryti tai dinamiška, reikia rankiniu būdu pereiti per visus įrašus ir laukus, naudojant buferius ir PUT sakinį:

// Dynamic Export Example  
CREATE BUFFER hBuffer FOR TABLE cTable. 

CREATE QUERY hQuery. 
hQuery:SET-BUFFERS(hBuffer). 
hQuery:QUERY-PREPARE("FOR EACH " + cTable + " NO-LOCK"). 
hQuery:QUERY-OPEN(). 
hQuery:GET-FIRST().  

OUTPUT TO VALUE(cFileName).   

DO WHILE NOT hQuery:QUERY-OFF-END: 
    IF hQuery:QUERY-OFF-END THEN LEAVE. 

    DO iCount = 1 TO hBuffer:NUM-FIELDS: 
        hField = hBuffer:BUFFER-FIELD(iCount). 
        PUT UNFORMATTED (IF iCount > 1 THEN "," ELSE "") 
                        hField:BUFFER-VALUE. 
    END. 
    PUT SKIP. 

    hQuery:GET-NEXT(). 
END.  

OUTPUT CLOSE. 
hQuery:QUERY-CLOSE().  

Ši versija veikia, tačiau turi kompromisų. Kadangi naudojamas PUT, reikia rankiniu būdu tvarkyti skirtuką, laukų eiliškumą ir formatavimą. Tai taip pat reiškia, kad jūs tiesiogiai atsakote už tai, kaip atrodys eksportuoti duomenys, o tai padidina klaidų tikimybę ir apsunkina kodo priežiūrą.

Naujasis eksportas, paremtas buferiais (12.8 versija)

Tai buvo tradiciniai duomenų perkėlimo būdai – tvirti, bet su savais apribojimais. Su Progress OpenEdge 12.8 versija programuotojai pagaliau gauna švaresnį ir dinamiškesnį būdą tvarkyti duomenų eksportą ir importą, naudojant buferius.

Anksčiau duomenų eksportas reiškė rankinį perėjimą per kiekvieną lauką, štai taip:

DO iCount = 1 TO hBuffer:NUM-FIELDS: 
    hField = hBuffer:BUFFER-FIELD(iCount). 
    PUT UNFORMATTED (IF iCount > 1 THEN "," ELSE "") 
                     hField:STRING-VALUE. 
END.  

Dabar tai – viena eilutė:

hBuffer:BUFFER-EXPORT().

BUFFER-EXPORT metodas automatiškai eksportuoja visus buferio duomenis ir leidžia pritaikyti parametrus, tokius kaip skirtukas, laukų pasirinkimas, LOB praleidimas ir kt. Jis veikia tiek statinėse, tiek dinaminėse užklausose ir yra žymiai greitesnis rašyti bei prižiūrėti.

Vienintelis apribojimas pasireiškia, kai reikia eksportuoti skaičiuojamus ar išvestinius laukus, kurie nėra tiesiogiai saugomi duomenų bazėje. Tai galite tvarkyti dviem būdais:

  • Naudoti temp-table su skaičiuojamais laukais.
  • Sujungti BUFFER-EXPORT su tradiciniu EXPORT.

Štai pavyzdys, naudojant temp-table su skaičiuojamu lauku:

/* Example: Calculated fields using a temp-table */ 
DEFINE TEMP-TABLE ttOrder NO-UNDO LIKE Order 
    FIELD DiscountPct AS DECIMAL FORMAT ">>9.99". /* Additional calculated field */  

OUTPUT TO VALUE("orders.csv").  

FOR EACH Order NO-LOCK: 
    /* Create one record in ttOrder per Order */ 
    CREATE ttOrder. 
    BUFFER-COPY Order TO ttOrder.  

    RUN calculateFields. 

    /* Export row */ 
    BUFFER ttOrder:BUFFER-EXPORT(). 
    DELETE ttOrder. 
END.   

OUTPUT CLOSE.   

PROCEDURE calculateFields: 
    DEFINE VARIABLE dTotalOrderPrice AS DECIMAL NO-UNDO. 
    DEFINE VARIABLE dOrderPrice      AS DECIMAL NO-UNDO. 
    DEFINE VARIABLE dTotalDiscount   AS DECIMAL NO-UNDO. 

    /* Business logic calculations: Sum up line totals and discounts */ 
    FOR EACH OrderLine NO-LOCK WHERE OrderLine.OrderNum EQ Order.OrderNum: 
        ASSIGN 
            dOrderPrice      = OrderLine.Price * OrderLine.Qty 
            dTotalOrderPrice += dOrderPrice 
            dTotalDiscount   += dOrderPrice * (OrderLine.Discount / 100). 
    END. 

    /* Calculate the discount percentage */ 
    ttOrder.DiscountPct = IF dTotalOrderPrice NE 0 
                           THEN 100 * (dTotalDiscount) / dTotalOrderPrice 
                          ELSE 0. 
END PROCEDURE.  

Sukuriame temp-table, atspindinčią Order lentelę, ir pridedame papildomą lauką DiscountPct. Kiekvienam užsakymui nukopijuojame įrašą į temp-table, apskaičiuojame reikšmę ir tuomet eksportuojame naudodami BUFFER-EXPORT.

Tokiu būdu eksportuotas failas turi tiek originalius, tiek skaičiuojamus laukus, su minimaliu kodu ir be poreikio rankiniu būdu pereiti per laukus. Dabar panagrinėkime, kaip OpenEdge 12.8 veikia, palyginti su senesniais metodais.

Veikimas: koks jis iš tikrųjų greitas?

Viena įdomiausių šios funkcijos dalių – kaip ji veikia praktikoje.

Norėdami pamatyti, kaip naujasis būdas lyginasi su kitais, testavome duomenų eksportą Progress OpenEdge 12.8 versijoje, naudodami 4 skirtingus metodus:

  • naudojant Buffer-Export;
  • eksportuojant JSON su temp-tables;
  • eksportuojant XML su temp-tables;
  • naudojant put unformatted.

Kadangi Export ir Import sakiniai nepalaiko dinaminio eksportavimo, jie buvo pakeisti PUT UNFORMATTED versija palyginimui.

Tikėtasi, kad BUFFER-EXPORT veiks panašiai kaip PUT UNFORMATTED, o JSON ir XML eksportai bus lėtesni dėl papildomos duomenų konvertavimo apkrovos.

Testavimui naudojome modifikuotą sports2020 duomenų bazę, kurioje buvo žymiai daugiau duomenų nei standartinėje versijoje. Testinė duomenų bazė buvo apie 350 MB, palyginti su įprastais 13–15 MB.

Specialūs duomenų tipai, tokie kaip BLOB, CLOB, MEMPTR ir LONGCHAR, buvo atmesti, kad testas išliktų nuoseklus. Visos procedūros buvo beveik identiškos, vienintelis skirtumas – išvesties metodas.

Ir rezultatai buvo netikėti:

Pilnos duomenų bazės eksportui į CSV/JSON/XML užtruko:

  • Buffer-Export: 36,2 sekundės iki CSV.
  • JSON eksportas naudojant temp-tables: 56,6 sekundės iki JSON.
  • XML eksportas naudojant temp-tables: 73,8 sekundės iki XML.
  • Put unformatted: 86,8 sekundės iki CSV.

Rezultatai parodė, kad BUFFER-EXPORT metodas buvo žymiai greitesnis – užtruko mažiau nei perpus trumpiau nei PUT UNFORMATTED.

Kaip ir tikėtasi, eksportavimas į JSON ar XML užtruko ilgiau, nes duomenis pirmiausia reikėjo įkelti į temp-tables, o tuomet įrašyti į failą. XML taip pat atsiliko nuo JSON, kas logiška, nes XML yra žymiai daugiažodis (verbose) formatas.

Trumpai tariant, BUFFER-EXPORT pasiūlė geriausią greičio, paprastumo ir lankstumo balansą.

Metodų santrauka: senas vs naujas

Metodas Privalumai Trūkumai
Įrankiai (.d failai) Greitas, patikimas, plačiai naudojamas Griežtas formatas, tik pilno lentelės eksportai
Temp-tables (JSON/XML) Lankstus, skaitomas, puikiai tinka API ir moderniai integracijai Sunaudoja daug atminties dideliems duomenų rinkiniams, reikalauja partijavimo
ABL EXPORT/IMPORT Pritaikomas ir lengvai suprantamas Daugiažodis, statinis, netinka dinaminiam eksportui
12.8 buferiai Greitas, glaustas, palaiko tiek statines, tiek dinamines užklausas Naujesnė funkcija su ribotais bendruomenės pavyzdžiais

Išvada: Progress OpenEdge 12.8 paruoštas perimti vairą

12.8 versija žymi tikrą pokytį tame, kaip programuotojai tvarko duomenų perkėlimą. Naujieji buferiais paremti eksporto ir importo metodai daro darbą su duomenimis švaresnį ir modernesnį: mažiau rankinio ciklų rašymo, mažiau apėjimo sprendimų ir žymiai greitesni rezultatai.

Be to, BUFFER-EXPORT suteikia tvirtą paprastumo ir galios balansą. Jis:

  • pasiekia aukštą veikimą su minimaliu kodu;
  • išlaiko aiškią tradicinio EXPORT ir IMPORT logiką;
  • sklandžiai veikia tiek statiniame, tiek dinaminiame kontekste;
  • leidžia lengvai įtraukti arba praleisti konkrečius laukus.

Tai daro buffer handles geriausiu pasirinkimu Progress OpenEdge projektams, kurie perkelia duomenis per kodą ir kuriems reikia lankstumo bei plečiamumo.

Nors jie nepakeičia temp-tables struktūrizuotam JSON ar XML eksportui, jie efektyviai perima tradicinių EXPORT ir IMPORT sakinių vaidmenį.

Tikimės, kad tai suteikė aiškesnį vaizdą, kaip naujasis metodas lyginasi praktikoje. Jei dirbate su Progress OpenEdge ir reikia ekspertų pagalbos, mūsų komanda pasiruošusi padėti – užsisakykite konsultaciją.

Dažniausiai užduodami klausimai

Kas yra BUFFER-EXPORT Progress OpenEdge 12.8 versijoje?

Tai naujas metodas, leidžiantis vienu sakiniu eksportuoti visus buferio duomenis, automatiškai tvarkant skirtukus, laukų pasirinkimą ir LOB praleidimą, be poreikio rankiniu būdu rašyti ciklą per kiekvieną lauką.

Ar BUFFER-EXPORT greitesnis už temp-tables ar PUT UNFORMATTED?

Taip. Testuose BUFFER-EXPORT eksportavo pilną duomenų bazę į CSV per 36,2 sekundes, o tai buvo žymiai greičiau nei PUT UNFORMATTED (86,8 s), JSON eksportas su temp-tables (56,6 s) ar XML eksportas su temp-tables (73,8 s).

Ar BUFFER-EXPORT pakeičia temp-tables struktūrizuotam JSON ar XML eksportui?

Ne pilnai. BUFFER-EXPORT puikiai tinka greitam, paprastam eksportui (pvz., CSV), tačiau temp-tables vis dar geriausiai tinka struktūrizuotiems JSON ar XML formatams ir skaičiuojamų laukų apdorojimui.

Kaip eksportuoti skaičiuojamus laukus naudojant BUFFER-EXPORT?

Kadangi BUFFER-EXPORT eksportuoja tik tiesiogiai duomenų bazėje saugomus laukus, skaičiuojamiems laukams reikia naudoti temp-table su papildomu lauku arba derinti BUFFER-EXPORT su tradiciniu EXPORT sakiniu.

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.