|
| WD19/WD20: Memory problems by using a query many times |
| Iniciado por guest, 30,may. 2015 13:56 - 10 respuestas |
| |
| | | |
|
| |
| Publicado el 30,mayo 2015 - 13:56 |
Hi all,
I have a window with a number of memory tables, filled by code, using a query, HExecuteQuery() and a FOR EACH of the query. In the FOR-EACH loop a global procedure gpGetPrijs() is called for each row in a memory table. In that global procedure a price is calculated and thereby are also (other) queries used. When the initial window table is filled a number of times (about 15 times, with about 1000 lines each time) the filling becomes very very slow. The problem is, in my opinion, in the call of gpGetPrijs(), because the processing time it's consuming becomes much longer after a while. I've noticed that the free RAM memory becomes less, each time. So there seems to be a memory leak. The problem is that I can't find the reason. Each query that I use is freed from memory by HFreeQuery() after use.
The problem is on my development laptop, using HFSQL Classic, but also (in test) on the customers computer using HFSQL/CS.
Anyone can help me to find the reason of the problem?
Example of filling the initial memory table: ++++++++++++++++++++++++++++++++++++++
liLine is int liMax is int liCount is int li8VrachtbriefID is 8-byte int li8RelatieArtikelID is 8-byte int lsRelatieNaam is string lcyBasisprijs is currency lcyEindprijs is currency TABLE_KAAS..DisplayEnabled = False IF NOT TABLE_KAAS..Empty THEN TableDeleteAll(TABLE_KAAS) QRY_Select_Vrachtbrief_forBilling.psFactuurgroepCode = csFGrpKaas QRY_Select_Vrachtbrief_forBilling.pdVanafBoekdatum = DateValid(EDT_Filter_VanafDatum) ? EDT_Filter_VanafDatum ELSE Null QRY_Select_Vrachtbrief_forBilling.pdTemBoekdatum = DateValid(EDT_Filter_TemDatum) ? EDT_Filter_TemDatum ELSE Null QRY_Select_Vrachtbrief_forBilling.piKleinerGelijkStatusVrachtbrief = csVBSBlokkeren // Verwijderd + Gefactureerd niet meer tonen IF HExecuteQuery(QRY_Select_Vrachtbrief_forBilling) THEN liMax = HNbRec(QRY_Select_Vrachtbrief_forBilling) FOR EACH QRY_Select_Vrachtbrief_forBilling liCount++ Gauge(liCount,liMax) IF QRY_Select_Vrachtbrief_forBilling.Aantal < 0 THEN IF WL.HReadSeekFirst(TblRelatie,TblRelatieID,QRY_Select_Vrachtbrief_forBilling.TblRelatieID_Verzend) THEN lsRelatieNaam = TblRelatie.Bedrijfsnaam END ELSE lsRelatieNaam = QRY_Select_Vrachtbrief_forBilling.Bedrijfsnaam END IF EDT_FILTER_TEKST ~= "" _OR_ (Position(QRY_Select_Vrachtbrief_forBilling.Intern_ID,Left(EDT_FILTER_TEKST),0,IgnoreCase) > 0 _OR_ ... Position(lsRelatieNaam,Left(EDT_FILTER_TEKST),0,IgnoreCase) > 0 _OR_ ... Position(QRY_Select_Vrachtbrief_forBilling.Intern_naam,Left(EDT_FILTER_TEKST),0,IgnoreCase) > 0 _OR_ ... Position(QRY_Select_Vrachtbrief_forBilling.Vrachtbriefnummer,Left(EDT_FILTER_TEKST),0,IgnoreCase) > 0) THEN // Alleen zonder prijs ? li8VrachtbriefID = QRY_Select_Vrachtbrief_forBilling.TblVrachtbriefID (lcyBasisprijs,lcyEindprijs,li8RelatieArtikelID) = gpGetPrijs(csFGrpKaas,li8VrachtbriefID) liLine = TableAddLine(TABLE_KAAS,QRY_Select_Vrachtbrief_forBilling.TblVrachtbriefID) IF liLine > 0 THEN IF QRY_Select_Vrachtbrief_forBilling.Aantal < 0 THEN TABLE_KAAS.COL_RELATIEID[liLine] = QRY_Select_Vrachtbrief_forBilling.TblRelatieID_Verzend ELSE TABLE_KAAS.COL_RELATIEID[liLine] = QRY_Select_Vrachtbrief_forBilling.TblRelatieID END TABLE_KAAS.COL_Relatie[liLine] = lsRelatieNaam TABLE_KAAS.COL_VRACHTBRIEFNR[liLine] = QRY_Select_Vrachtbrief_forBilling.Vrachtbriefnummer TABLE_KAAS.COL_VBKSTATUS[liLine] = QRY_Select_Vrachtbrief_forBilling.Status_vrachtbrief TABLE_KAAS.COL_ARTIKELNR[liLine] = QRY_Select_Vrachtbrief_forBilling.Intern_ID TABLE_KAAS.COL_ARTIKELID[liLine] = QRY_Select_Vrachtbrief_forBilling.TblArtikelID TABLE_KAAS.COL_OMSCHRIJVING[liLine] = QRY_Select_Vrachtbrief_forBilling.Intern_naam TABLE_KAAS.COL_REFERENTIE[liLine] = QRY_Select_Vrachtbrief_forBilling.Regelreferentie TABLE_KAAS.COL_AANTAL[liLine] = QRY_Select_Vrachtbrief_forBilling.Aantal TABLE_KAAS.COL_KG[liLine] = QRY_Select_Vrachtbrief_forBilling.kilos TABLE_KAAS.COL_AFLEVERDATUM[liLine] = QRY_Select_Vrachtbrief_forBilling.Boekdatum TABLE_KAAS.COL_BASISPRIJS[liLine] = lcyBasisprijs TABLE_KAAS.COL_EindPrijs[liLine] = lcyEindprijs TABLE_KAAS.COL_RELATIEARTIKELID[liLine] = li8RelatieArtikelID IF TABLE_KAAS.COL_BASISPRIJS[liLine] = 0 THEN TABLE_KAAS[liLine]..Color = LightRed ELSE IF TABLE_KAAS.COL_AANTAL[liLine] < 0 THEN TABLE_KAAS[liLine]..Color = LightBlue ELSE TABLE_KAAS[liLine]..Color = DefaultColor END END END END END END HFreeQuery(QRY_Select_Vrachtbrief_forBilling) TABLE_KAAS..DisplayEnabled = True Gauge()
Code of the global procedure: ++++++++++++++++++++++++++++++++++++++ // Summary: // Syntax: //[ = ] gpGetPrijs ( is string, is 8-byte int) // // Parameters: // psFactuurcode (ANSI string): // pi8VrachtbriefID (8-byte int): // Return Value: // multi-value: // None // // For instance: // Indicate an example. // // pi8RelatieID (8-byte int): // pi8ArtikelID (8-byte int): // pdAfleverDatum (date): PROCEDURE gpGetPrijs(psFactuurcode is string, pi8VrachtbriefID is 8-byte int) liRegel is int liDagen is int liFaseDagen is int li8RelatieArtikelID is 8-byte int li8PrijslijstID is 8-byte int li8EenheidID is 8-byte int ldDatum is Date lsEenheid is string lcyHulpPrijs is currency //= 0 lcyBasisprijs is currency //= 0 lcyPrijs2 is currency //= 0 lcyPrijs3 is currency //= 0 lcyPeriodiekeprijs is currency //= 0 lcyEindPrijs is currency //= 0 lcyIndrooggewicht is currency IF WL.HReadSeekFirst(TblVrachtbrief,TblVrachtbriefID,pi8VrachtbriefID) THEN // Betreft het een retouren vrachtbrief ? // LET OP: als er in TblRetourgegevens een originele vrachtbon + data is vastgelegd OF los een originele // productiedatum, leverdatum en ArtikelID, dan moeten die gebruikt worden voor het bepalen van de prijs. // Dit omdat de prijs gebruikt moet worden van de factuur van de originele levering en NIET diegene die // gebaseerd is op de gegevens van de retouren. Gevonden gegevens overschrijven die van de retour vrachtbrief, // dus deze NIET herschrijven ! IF TblVrachtbrief.Aantal < 0 _AND_ WL.HReadSeekFirst(TblRetourgegevens,TblVrachtbriefID,TblVrachtbrief.TblVrachtbriefID) THEN TblVrachtbrief.TblArtikelID = TblRetourgegevens.Originele_ArtikelID TblVrachtbrief.Boekdatum = TblRetourgegevens.Originele_Leverdatum TblVrachtbrief.Productiedatum = TblRetourgegevens.Originele_Productiedatum END SWITCH psFactuurcode CASE csFGrpKaas IF TblVrachtbrief.Aantal < 0 THEN QRY_Select_RelatieArtikelKaas_perRelatieSimple.piRelatieID = TblVrachtbrief.TblRelatieID_Verzend ELSE QRY_Select_RelatieArtikelKaas_perRelatieSimple.piRelatieID = TblVrachtbrief.TblRelatieID END QRY_Select_RelatieArtikelKaas_perRelatieSimple.piArtikelID = TblVrachtbrief.TblArtikelID QRY_Select_RelatieArtikelKaas_perRelatieSimple.pdMaxVanafDatum = TblVrachtbrief.Boekdatum[[1 TO 8]] IF HExecuteQuery(QRY_Select_RelatieArtikelKaas_perRelatieSimple) THEN IF WL.HReadLast(QRY_Select_RelatieArtikelKaas_perRelatieSimple,"",hNoRefresh) THEN li8RelatieArtikelID = QRY_Select_RelatieArtikelKaas_perRelatieSimple.TblRelatieArtikelID END END HFreeQuery(QRY_Select_RelatieArtikelKaas_perRelatieSimple) IF li8RelatieArtikelID > 0 _AND_ WL.HReadSeekFirst(TblRelatieArtikel,TblRelatieArtikelID,li8RelatieArtikelID) THEN lcyBasisprijs = TblRelatieArtikel.Basisprijs lcyHulpPrijs = TblRelatieArtikel.Basisprijs lcyHulpPrijs -= Round(TblRelatieArtikel.Basisprijs * TblRelatieArtikel.Kortingpercentage / 100,4) IF TblRelatieArtikel.GebruikTijdelijkeKorting THEN IF NOT DateValid(TblRelatieArtikel.TijdelijkeKortingDatumTem) _OR_ TblVrachtbrief.Boekdatum <= TblRelatieArtikel.TijdelijkeKortingDatumTem THEN lcyHulpPrijs -= TblRelatieArtikel.TijdelijkeKortingBedragPerKg END END IF TblRelatieArtikel.GebruikGewichtsKorting THEN IF TblVrachtbrief.kilos >= TblRelatieArtikel.GewichtsKortingVanafKg THEN lcyHulpPrijs -= TblRelatieArtikel.GewichtsKortingBedragPerKg END END IF TblRelatieArtikel.GebruikLaadkosten THEN lcyHulpPrijs += TblRelatieArtikel.LaadkostenBedragPerKg END IF TblRelatieArtikel.GebruikVerpakkingskosten THEN lcyHulpPrijs += TblRelatieArtikel.VerpakkingskostenBedragPerKg END ldDatum = TblVrachtbrief.Productiedatum[[1 TO 8]] IF DateValid(ldDatum) THEN liDagen = DateDifference(ldDatum,TblVrachtbrief.Boekdatum[[1 TO 8]]) IF TblRelatieArtikel.VoorrRenteUitvalVanafDag > 0 THEN liDagen -= (TblRelatieArtikel.VoorrRenteUitvalVanafDag - 1) END IF liDagen > 0 THEN // <= 0 betekent dat het minimum aantal kostendagen nog niet bereikt is ! IF TblRelatieArtikel.GebruikVoorraadkosten THEN lcyHulpPrijs += Round(TblRelatieArtikel.VoorraadkostenBedragPerKgDag * liDagen,4) END IF TblRelatieArtikel.GebruikRentekosten THEN lcyHulpPrijs += Round((TblRelatieArtikel.Basisprijs * TblRelatieArtikel.RentekostenPercPerDag / 100) * liDagen,4) END IF TblRelatieArtikel.GebruikUitvalkosten THEN lcyHulpPrijs += Round((TblRelatieArtikel.Basisprijs * TblRelatieArtikel.UitvalkostenPercPerDag / 100) * liDagen,4) END IF HSeekFirst(TblIndroogprofiel,TblRelatieArtikelID,TblRelatieArtikel.TblRelatieArtikelID) THEN liDagen = DateDifference(ldDatum,TblVrachtbrief.Boekdatum[[1 TO 8]]) QRY_Select_Indroogprofiel.piRelatieArtikelID = TblRelatieArtikel.TblRelatieArtikelID IF HExecuteQuery(QRY_Select_Indroogprofiel) THEN liRegel = 0 lcyIndrooggewicht = 0 FOR EACH QRY_Select_Indroogprofiel liRegel++ IF liRegel = 1 THEN // Eerste regel, begin met tellen vanaf deze dag IF QRY_Select_Indroogprofiel.VanafDag > 0 THEN liDagen -= (QRY_Select_Indroogprofiel.VanafDag - 1) END END liFaseDagen = (QRY_Select_Indroogprofiel.TemDag - QRY_Select_Indroogprofiel.VanafDag + 1) IF liDagen >= liFaseDagen THEN lcyIndrooggewicht += Round(liFaseDagen * 1 * QRY_Select_Indroogprofiel.Waarde,3) liDagen -= liFaseDagen ELSE lcyIndrooggewicht += Round(liDagen * 1 * QRY_Select_Indroogprofiel.Waarde,3) liDagen = 0 BREAK END END // Let op, het is een percentage, dus indroogbedrag later vermenigvuldigen met aantal kg. lcyHulpPrijs += Round(TblRelatieArtikel.Basisprijs * (lcyIndrooggewicht / 100),4) // / abs(TblVrachtbrief.kilos),4) END HFreeQuery(QRY_Select_Indroogprofiel) END END // Einde extra kosten obv. extra-kostendagen END END lcyEindPrijs = lcyHulpPrijs RESULT (lcyBasisprijs,lcyEindPrijs,li8RelatieArtikelID) OTHER CASE END END |
| |
| |
| | | |
|
| | |
| |
| Publicado el 30,mayo 2015 - 14:05 |
Hello Stefan
HCancelDeclaration is supposed to also free the resources used by a query so perhaps give that a try.
Regards Al |
| |
| |
| | | |
|
| | |
| |
| Publicado el 30,mayo 2015 - 14:33 |
Hi everybody
to AL: he is already doing that, as hcanceldeclaration=hfreequery (just a different name)
to Stefan: the first thing I would try is to add a multitask(-5) after each hfreequery, to give the system some time to do its work at that level... Let us know if that makes a difference
Best regards |
| |
| |
| | | |
|
| | |
| |
| Publicado el 31,mayo 2015 - 20:04 |
Fabrice,
beside the fact that the MultiTask(-5) after the HFreeQuery() slows down my program til an unacceptable speed (doesn't matter for a test, but unacceptable for my customer), the speed still become slower and slower after more call's of the global procedure gpGetPrijs().
I've also tried to use HFreeQuery() only at the and of the init-of-table-proces (without MultiTask(-5) and with MultiTask(-5). The processing time of the procedure gpGetPrijs() starts at 0 / 1 hundreds of a second and after a while (14-15 times filling the memory table, about 8600 calls of procedure gpGetPrijs) the processing time increases to over the 500 hundreds of a second.
For your information, this is the SQL-code of the queries in procedure gpGetPrijs(), where the second query is only executed after checking for records by HSeekFirst():
SELECT TblRelatieArtikel.TblRelatieArtikelID AS TblRelatieArtikelID, TblRelatieArtikel.TblRelatieID AS TblRelatieID, TblRelatieArtikel.DatumVanaf AS DatumVanaf, TblRelatieArtikel.GebruikDatumTem AS GebruikDatumTem, TblRelatieArtikel.DatumTem AS DatumTem, TblRelatieArtikel.Basisprijs AS Basisprijs, TblRelatieArtikel.TblArtikelID AS TblArtikelID FROM TblRelatieArtikel WHERE TblRelatieArtikel.TblRelatieID = {piRelatieID} AND TblRelatieArtikel.TblArtikelID = {piArtikelID} AND TblRelatieArtikel.DatumVanaf <= {pdMaxVanafDatum} AND TblRelatieArtikel.DatumTem = {pdTemDatum} AND TblRelatieArtikel.DatumVanaf >= {pdVanafDatum} ORDER BY DatumVanaf ASC
++++++++++++++++++++++++++++++++++++++++++++++++++++
SELECT TblIndroogprofiel.TblIndroogprofielID AS TblIndroogprofielID, TblIndroogprofiel.TblRelatieArtikelID AS TblRelatieArtikelID, TblIndroogprofiel.VanafDag AS VanafDag, TblIndroogprofiel.TemDag AS TemDag, TblIndroogprofiel.Waarde AS Waarde FROM TblIndroogprofiel WHERE TblIndroogprofiel.TblRelatieArtikelID = {piRelatieArtikelID} ORDER BY VanafDag ASC |
| |
| |
| | | |
|
| | |
| |
| Publicado el 31,mayo 2015 - 22:43 |
hi
another thing to try is to block the display of the window during the filling of the table, to see if the problem comes from there... there is a window property for that (but I don't remember it right now)
Block it before tabledeleteall and unblock after the end of your loop
Best regards |
| |
| |
| | | |
|
| | |
| |
| Publicado el 01,junio 2015 - 21:17 |
Hi Fabrice,
I already use these blocking of the display of the table:
TABLE_KAAS..DisplayEnabled = False
with
TABLE_KAAS..DisplayEnabled = True
after the end of the loop. |
| |
| |
| | | |
|
| | |
| |
| Publicado el 01,junio 2015 - 23:35 |
Hi Stefan,
ok, so the simplest things have been put out of the way... Now is the time to test... Try and create a test window and do the following: 1. a button with a loop and a query inside, and a chrono to verify if looping on a query creates the problem
if -NO- 2. a button AND a table, in the button a loop doing he quey AND adding in the table, with a chrono again
if -YES- 3. a button doing a loop adding in the table but without the query
Do first this testing with the same query as now... If you isolate the problem as being the query, then do it with a much simpler query and compare
The results should tell us what to do next (or at least give us a test project to send pcsoft support)
Best regards |
| |
| |
| | | |
|
| | |
| |
| Publicado el 03,junio 2015 - 16:36 |
Le 30/05/2015 11:56, Stefan Bentvelsen a écrit :
Hi all,
I have a window with a number of memory tables, filled by code, using a query, HExecuteQuery() and a FOR EACH of the query. In the FOR-EACH loop a global procedure gpGetPrijs() is called for each row in a memory table. In that global procedure a price is calculated and thereby are also (other) queries used. When the initial window table is filled a number of times (about 15 times, with about 1000 lines each time) the filling becomes very very slow. The problem is, in my opinion, in the call of gpGetPrijs(), because the processing time it's consuming becomes much longer after a while. I've noticed that the free RAM memory becomes less, each time. So there seems to be a memory leak. The problem is that I can't find the reason. Each query that I use is freed from memory by HFreeQuery() after use.
The problem is on my development laptop, using HFSQL Classic, but also (in test) on the customers computer using HFSQL/CS.
Hi, I had the same kind of issues. It was caused by using memory tables (and not by HexecuteQuery). I solved it by using memory arrays. In my case, processing time went from 3 min to less than 1 sec.
Regards,
Fred |
| |
| |
| | | |
|
| | |
| |
| Publicado el 08,junio 2015 - 20:45 |
Hi Fabrice,
it took me some time to continue the testing, but here we are.
I made a button to loop and execute the first query of the global procedure gpGetPrijs(). After 10400 times, the execution time of het query increases from 0 or 1 hundred of a second to 111 at the 10429 execution. In my opinion, I've isolated the problem to this query.
I will try another, simpler query and come back with results. |
| |
| |
| | | |
|
| | |
| |
Miembro registrado 18 mensajes |
|
| Publicado el 10,junio 2015 - 19:38 |
Fredo. What do you mean by memory arrays? Can you give a quick example?
I'm currently using the following code. I'm trying to speed it up. The query runs very fast on client/server, but the TableAddLine() takes too long.
IF HExecuteSQLQuery(dataSourceVariable, sqlQuery) THEN TableAddLine(Table,dataSourceVariable.ID,dataSourceVariable.field1,dataSourceVariable.field2 END |
| |
| |
| | | |
|
| | |
| |
| Publicado el 11,junio 2015 - 13:36 |
Hi,
I would try this: 1) Use SQL instead of querys (HExecuteSQLQuery instead HExecuteQuery); 1.1) If possible, use a single data source for each HExecuteSQLQuery and always free it after using it; Also, consider closing the used files (HCLOSE); 2) Use "normal" FOR instead of FOR EACH; 3) Clean all used variables at the end of the procedure (VariableReset);
Bruno |
| |
| |
| | | |
|
| | | | |
| | |
|