Autor Téma: Array DML (FireDAC) ->Zostáva neuvoľnená pamäť  (Přečteno 2358 krát)

Offline miroB

  • Guru
  • *****
  • Příspěvků: 514
  • Karma: 17
    • Verze Delphi: D1,2,3,4,7,2005,2009, XE8,S,B,T10.2.2 Pro
Robím prenos dát z Excelu do SQLite:
  • Zdroj. súbor xlsx má veľkosť 77 MB. Program funguje.
    PeakWorkingSetSize =  767 980 KB ( sheet xml po rozbalení cca 530 MB, môj buffer 210 MB )
  • Ak program prenosu ukončím ešte vo fáze pred exportom do databázy, ( +vykonám Clear ), vráti sa na pekných 4,5 MB (Task Manager)
  • V prípade exportu do SQLite, s využitím "FDQuery1.Params.ArraySize" (veľkosť 10 000) všetko prebehne ako má. Cca 500k riadkov a 12mil buniek, je v databáze (Komplet celé za menej ako 10 sekúnd ).
    Lenže program po skončení nemá 4,5 MB, ale veľkosť zostane vysieť na 53 MB. (Task Manager).
  • Je fakt, že mám aj dbGrid. Lenže jeho zavretie a odpojenie moc nepomôže.
    Dlho som si myslel, že mám nejakú Memory leak (pracujem s pointerami).
  • Potom ma napadlo killnúť DM (DataModule ), so všetkými FireDAC komponentami (1 Conn, 2 Query) a jedným TDataSet-om. Nič iné v DM nie je. Určite žiadny môj buffer.
  • Otravných 50 MB sa pekne vrátilo na pôvodných cca 4.5 MB.
  • Preto si myslím, že "na vine" sú FireDAC komponenty, kde "zostalo čosi visieť", nejaký ten buffer.
    Bežné "Query.Active:=False" a "Conn.Connected:=false", takmer nijak nepomohlo.
Nedá sa spraviť nejaký FLUSH, či niečo podobné?
Využité Array DML. (Params.BindMode = pbByNumber)
Viď http://docwiki.embarcadero.com/RADStudio/Rio/en/Array_DML_(FireDAC)
« Poslední změna: 09-07-2019, 12:20:09 od miroB »

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 4342
  • Karma: 38
    • Verze Delphi: XE7 professional
Re:Array DML (FireDAC) ->Zostáva neuvoľnená pamäť
« Odpověď #1 kdy: 09-07-2019, 12:39:33 »
Ten DataSet si preveril?
Delphi XE7, FireBird
Expert na kladenie nejasne formulovaných otázok.

Offline miroB

  • Guru
  • *****
  • Příspěvků: 514
  • Karma: 17
    • Verze Delphi: D1,2,3,4,7,2005,2009, XE8,S,B,T10.2.2 Pro
Re:Array DML (FireDAC) ->Zostáva neuvoľnená pamäť
« Odpověď #2 kdy: 09-07-2019, 13:21:15 »
DataSet sám o sebe nepomohol. Ten som odstavil už pri začiatku skúmania.
Keby som riešil StringGrid, je jasné, že ten by spotreboval veľkú pamäť.
Ale mám dbGrid, ktorý načítava nové riadky až na požiadanie.
Mám dve FDQuery:
  • Prezerací s nastaveniami pre dbGrid (aby čítal data až na požiadanie)
  • INSERT INTO Query, mám nastavený na rýchle načítavanie.
Upresňujem výsledok pokusu:
Stačilo killnúť, len druhé query (INSERT INTO) a pamäť bola vrátená systému.
Aby nevzniklo podozrenie, naplnenie DML Array prebieha v cykle, poctivo striehnem ArraySize, potom spúšťam Exec. Transakcie dávam 1:1 s exec.
V prípade, že program vypadne s neukončenou transakciou, z cyklu, tak korektne s adekvátnou veľkosťou spustím Exec a na záver Commitnem.
« Poslední změna: 09-07-2019, 13:22:48 od miroB »

Offline miroB

  • Guru
  • *****
  • Příspěvků: 514
  • Karma: 17
    • Verze Delphi: D1,2,3,4,7,2005,2009, XE8,S,B,T10.2.2 Pro
Re:Array DML (FireDAC) ->Zostáva neuvoľnená pamäť
« Odpověď #3 kdy: 09-07-2019, 15:36:35 »
  • TFDBatchMove nemôžem použiť. Nemám tam dataset. (Je to vlastné riešenie. Parsovanie xml 4 sekundy, Array DML 5 sekúnd). Výsledný SQLite súbor má 103 mega
  • Nechápem prečo nie je pamäť automaticky uvoľnená systému po prenose dát. Akonáhle dám Query.Freeje to OK
  • Pre pamäť používam PeakWorkingSetSize & spol. Výpis do podrobného logu. Pred a za každou zaujímavou funkciou.. V zásade veľmi dobre korešponduje s Task Managerom keď krokujem. Shválne pracujem s veľkým súborom. Každá akcia sa viditeľne prejaví. Hneď. Aj v Task Manageri.

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 2580
  • Karma: 133
    • Verze Delphi: D2007, XE3, DX10
Re:Array DML (FireDAC) ->Zostáva neuvoľnená pamäť
« Odpověď #4 kdy: 09-07-2019, 16:42:36 »
  • Pre pamäť používam PeakWorkingSetSize & spol. Výpis do podrobného logu. Pred a za každou zaujímavou funkciou.. V zásade veľmi dobre korešponduje s Task Managerom keď krokujem.
Vypisuj si obsah stavu pameti aplikace, jak pise Delphin: http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/System__TMemoryManagerState.html

Offline miroB

  • Guru
  • *****
  • Příspěvků: 514
  • Karma: 17
    • Verze Delphi: D1,2,3,4,7,2005,2009, XE8,S,B,T10.2.2 Pro
Re:Array DML (FireDAC) ->Zostáva neuvoľnená pamäť
« Odpověď #5 kdy: 09-07-2019, 19:01:29 »
Pracuj s memory managerem, ne s operacnim systemem. Memory manager si totiz muze ponechat nektere bloky pameti pro budouci pouziti (oznaci si je za volne, ale OS je nevrati).
Ak som použil _PROCESS_MEMORY_COUNTERS štruktúru pre zisťovanie pamäti, tak to teda nebolo v poriadku? (PeakWorkingSetSize, WorkingSetSize, GetCurrentSetSize )
Na obr. prikladám malý výber z cca 30-50 záznamov logu.

Inak ma napadlo, že keď zrovna len Query "INSERT INTO" prerobím na čiste Runtime, na záver výpočtu ho logicky uvoľním. A bude vymaľované.
Ak mi také chovanie nezahlási chybu, zjavne uvoľní pamäť aj pre Task Manager, všetky údaje budú v SQLite, tak som asi spokojný.
Alebo mám skôr očakávať skrytú zradu?

Bez prerušenia programu som schopný preniesť v sérii všetky hárky Excelu a aj viaceré ďalšie celé xlsx súbory.

Pozerám aj na radu PF1957. GetMemoryManagerState. Našiel som v kompe aj nejaké vzory.
Lenže už sa mi do toho moc nechce. Som prepracovaný. Potrebujem produkovať ďalšie výsledky.
Ale keď sa ukáže, že je to treba, tak sa ešte dozadu premôžem.

Offline miroB

  • Guru
  • *****
  • Příspěvků: 514
  • Karma: 17
    • Verze Delphi: D1,2,3,4,7,2005,2009, XE8,S,B,T10.2.2 Pro
Re:Array DML (FireDAC) ->Zostáva neuvoľnená pamäť
« Odpověď #6 kdy: 09-07-2019, 19:44:01 »
..
P.S. pro TFDBatchMove si muzes napsat vlastni vstupni ci vystupni objekt (on ma uz ted tusim parser CSV v zakladni vybave).
OK, vidím:
https://stackoverflow.com/questions/33045414/firedac-how-to-set-up-tfdbatchmove-with-data-set-reader-writer
a
http://docwiki.embarcadero.com/CodeExamples/Seattle/en/FireDAC.TFDBatchMove_Sample
Bude však lepšie, keď zachovám "neštandardné" riešenie.
Dôvod je bližšie vysvetlený tu: https://forum.delphi.cz/index.php/topic,16290.0.html
V skratke: Nechcem byť "vyrušovaný" kontrolou typu údajov. V prípade DataSet sa tomu zrejme nevyhnem..
SQLite som nevedel prísť na chuť, pre zásadný problém s typom dát. Bolo tu už k téme napísané hodne. Je fakt, že FireDAC pre SQLite, tú voľnosť datových typov "drôtuje". Bráni jej, ale našťastie nie celkom. To využívam v privátnom riešení, pri Array DML.
No a užívateľ, ktorý sa prispôsobí SQLite filozofii, má potom nekonečné možnosti experimentovania.
Aj v oblasi písania SQL-ov.
Príklad využitia:
Sú firmy, ktoré potrebujú poznať nielen číselné hodnoty stĺpca, ale aj prípadné chybové hodnoty.
Jediná mne známa relačná databáza, ktorá zvládne v stĺpci čísla a aj chybové kódy, bez nutnosti dvoch samostatných stĺpcov je práve SQLite.
Výsledok je pôsobivý. Ak pracujete s číslami, chybové hodnoty sa tvária ako 0 (Nula).
Akonáhle použijete cca toto:
SELECT mojeCislo AS [mojeCislo::Text(12)] FROM XY
máte zobrazený zoznam chýb.
Prípadne možné doplniť obmedzením, cca takto:
WHERE NOT IsNumber( mojeCislo ) -- nie je presne odskusane. Verim že sa da
« Poslední změna: 09-07-2019, 19:59:34 od miroB »

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 4342
  • Karma: 38
    • Verze Delphi: XE7 professional
Re:Array DML (FireDAC) ->Zostáva neuvoľnená pamäť
« Odpověď #7 kdy: 09-07-2019, 19:58:28 »
Citace
Bez prerušenia programu som schopný preniesť v sérii všetky hárky Excelu a aj viaceré ďalšie celé xlsx súbory.
Ale ako som z Tvojho textu pochopil, tak pri prvej chybe pri Commit proces ukončíš a uložíš len čo prebehlo predtým. Z môjho pohľadu to je veľmi zle. Ja by som niečo také nikdy neurobil. Ak som to dobre pochopil, tak máš dve možnosti:
  • Buď uložíš celý hárok, alebo nič. Tak to riešim ja
  • Neuložíš chybné riadky. Ostatné uložíš. A vypíšeš oznam
Delphi XE7, FireBird
Expert na kladenie nejasne formulovaných otázok.

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 4342
  • Karma: 38
    • Verze Delphi: XE7 professional
Re:Array DML (FireDAC) ->Zostáva neuvoľnená pamäť
« Odpověď #8 kdy: 09-07-2019, 20:00:26 »
V tvojom odkaze boli uvedené príklady na ošetrenie chýb. Ale nie na Tvoj prípad. Ten zaujíma aj mňa.
Delphi XE7, FireBird
Expert na kladenie nejasne formulovaných otázok.

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 4342
  • Karma: 38
    • Verze Delphi: XE7 professional
Re:Array DML (FireDAC) ->Zostáva neuvoľnená pamäť
« Odpověď #9 kdy: 09-07-2019, 20:13:49 »
Ešte poznámočka. Ak budeš mať ArraySize = 1000 a v dávke mu pošleš len 500 príkazov, tak sa nič nedeje.
Delphi XE7, FireBird
Expert na kladenie nejasne formulovaných otázok.

Offline miroB

  • Guru
  • *****
  • Příspěvků: 514
  • Karma: 17
    • Verze Delphi: D1,2,3,4,7,2005,2009, XE8,S,B,T10.2.2 Pro
Re:Array DML (FireDAC) ->Zostáva neuvoľnená pamäť
« Odpověď #10 kdy: 09-07-2019, 20:20:37 »
V tvojom odkaze boli uvedené príklady na ošetrenie chýb. Ale nie na Tvoj prípad. Ten zaujíma aj mňa.
U mňa je to filozoficky jednoduché. Zatiaľ.
Nie je problém, že vznikne polotovar pri ukladaní.
Podstatné je, či celkove prebehne bez akejkoľvek chybovej hlášky. Prípadne skontroľujem ešte navyše aj počet riadkov na oboch stranách. Inak ho neaxceptujem.
Prenášam teraz tabuľku 1:1. NEROBÍM APPEND.
Ale ak by som sa zo širšieho hľadiska zamyslel a ten append išiel dorobiť, tak stále zostanem u tabuľky. Bude trebars temp, alebo InMemory ( obe SQLite umožňuje).
Alebo aj tretia možnosť, keď by som si nechcel "zašpiniť" hlavnú databázu, môžem vytvoriť samostatný dočasný SQLite súbor. Ten následne linknúť na hlavnú databázu.
Po kontrole, že prenos tabuľky prebehol komplet, (viď vyššie), príde krok 2.
V ňom sa už vysporiadam s appendom do cieľovej tabuľky prostriedkami databázy.

Offline miroB

  • Guru
  • *****
  • Příspěvků: 514
  • Karma: 17
    • Verze Delphi: D1,2,3,4,7,2005,2009, XE8,S,B,T10.2.2 Pro
Re:Array DML (FireDAC) ->Zostáva neuvoľnená pamäť
« Odpověď #11 kdy: 09-07-2019, 20:26:54 »
Ešte poznámočka. Ak budeš mať ArraySize = 1000 a v dávke mu pošleš len 500 príkazov, tak sa nič nedeje.
Nevadí. Mám to aj kvôli kontrole. Aj tak počítam inserty. Aby som vedel, či je požiadavka=0, alebo je viac ako 0.
Druhou kontrolou je aj otvorená transakcia. Takže ide o duplikovanú kontrolu.
Vzhľadom na to, že tabuľky budú spravidla asi 1000 krát menšie, ba ešte menšie.. mám určitú výkonovú rezervu.. Teoreticky sa prenos z 90% vykoná v rozmedzí 0.1 - 1.0 sekundy. Vrátane analýzy typov, konverzií, rozbaľovania a podobne.
Preto si môžem dovoliť určitý luxus v kontrole:)
« Poslední změna: 09-07-2019, 20:31:15 od miroB »

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 4342
  • Karma: 38
    • Verze Delphi: XE7 professional
Re:Array DML (FireDAC) ->Zostáva neuvoľnená pamäť
« Odpověď #12 kdy: 09-07-2019, 20:28:57 »
Tebe príkaz Query.Transaction.Rollback nedá DB do pôvodného stavu?
V Tvojom popise som nepochopil jednu vec. Ideš riadok po riadku a zakaždým urobíš Commit. Ak máš výnimku ukončíš to. Ak nie, tak to dokončíš a urobíš Exec. To mi hlava neberie. Z môjho pohľadu to je duplicitné uloženie údajov.
Delphi XE7, FireBird
Expert na kladenie nejasne formulovaných otázok.

Offline miroB

  • Guru
  • *****
  • Příspěvků: 514
  • Karma: 17
    • Verze Delphi: D1,2,3,4,7,2005,2009, XE8,S,B,T10.2.2 Pro
Re:Array DML (FireDAC) ->Zostáva neuvoľnená pamäť
« Odpověď #13 kdy: 09-07-2019, 20:33:59 »
Tebe príkaz Query.Transaction.Rollback nedá DB do pôvodného stavu?
V Tvojom popise som nepochopil jednu vec. Ideš riadok po riadku a zakaždým urobíš Commit. Ak máš výnimku ukončíš to. Ak nie, tak to dokončíš a urobíš Exec. To mi hlava neberie. Z môjho pohľadu to je duplicitné uloženie údajov.
Pozri sem:
http://docwiki.embarcadero.com/RADStudio/Rio/en/Array_DML_(FireDAC)
Example 1.
Mám ArraySize nastavený na 10 000. Takže pred EXEC prebehne 10 000 INSERT INTO príkazov.
V každom cykle len reagujem na stav, či treba iba zápis (insert into), alebo k nemu aj Exec a Commit.
Po exec robím Commit. ( Presne až po tých desiatich t. ) Po commit nastavím Begin Transaction..
Cyklus pokračuje.
Až po ukončení cyklu ešte kontrolujem, či niečo nezostalo na Commit-nutie.
Resp. či nie je otvorená transakcia.
Asi tak: Skáčem po 10t. Ale tabuľka nemá čistý násobok 10t (spravidla nikdy), tak zostanú nejaké drobné na záver.
« Poslední změna: 09-07-2019, 20:52:07 od miroB »

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 4342
  • Karma: 38
    • Verze Delphi: XE7 professional
Re:Array DML (FireDAC) ->Zostáva neuvoľnená pamäť
« Odpověď #14 kdy: 09-07-2019, 21:01:58 »
Citace
V každom cykle len reagujem na stav, či treba iba zápis (insert into), alebo k nemu aj Exec a Commit.
Predpokladám, že kontroluješ nejaké podmienky na základe ktorých sa rozhodneš. Tak mi to je jasnejšie. Len mi to trocha nesedí. Možno si sa iba zle vyjadril.
V mojom poňatí by to bolo takto. "V každom cykle len reagujem na stav, či treba iba zápis. Ak áno, tak urobím InsertInto a na konci cyklu Exec a Commit."
No nechajme to už tak. Ako Ťa poznám, tak to máš poriadne premyslené a vyskúšané ;)
Delphi XE7, FireBird
Expert na kladenie nejasne formulovaných otázok.