[Delphi] Insert / Append Record langzaam

Pagina: 1
Acties:
  • 228 views sinds 30-01-2008
  • Reageer

  • JoostMartijn
  • Registratie: December 2003
  • Laatst online: 17-04-2025
Hallo,

Ik ben een programma aan het schrijven dat gegevens uit een bestand leest. Dit werkt heel snel. NU het volgende probleem hoe kan ik zorgen dat de database transactie heel snel gaat. Nu duurt het 5 a 10 seconde om 300 records weg te schrijven. Ik heb het geprobeerd met appendrecord en met insertrecord, bij beide duurt het heel lang.

Heeft iemand goeie tips.

Het gaat om een interbase database(firebird). Voor dat ik de recordsinsert disable ik al de controls van de tabel.

Windsoft


  • whoami
  • Registratie: December 2000
  • Laatst online: 16:43
Waarom gebruik je niet gewoon INSERT SQL statements ?

Je opent toch ook niet voor ieder record dat je wilt inserten een nieuwe connectie ?

https://fgheysels.github.io/


Verwijderd

Wanneer je in Delphi Tables gebruikt op een SQL database (Interbase, MSSQL, Oracle, etc.) dan gebeurt op de database-laag van de client (BDE, DBExpress, ADO, etc.) ongeveer hetvolgende: er wordt een SELECT statement opgebouwd, deze wordt losgelaten op de database, en de resultset wordt gepresenteerd als 'table'.
Insert je nu een record via die table, dan krijgt die database-laag het druk:
- INSERT query opbouwen
- query uitvoeren
- SELECT query opnieuw uitvoeren om de table te verversen
- eventuele bookmarks bijwerken

En dat maal 300, dat kan even duren...

Dit kun je op meerdere manieren oplossen.

- whoami heeft al de meest voor de hand liggende genoemd: zelf 300x een INSERT query uitvoeren, en daarna de table eenmalig refreshen.

- Een TClientDataset gebruiken i.p.v. een TTable. Met een ClientDataset kun je de inhoud van een tabel in het geheugen van de client laden, en daarop de insert- en update-bewerkingen uitvoeren zoals je die gewend bent. Nadat de bewerkingen klaar zijn (die 300 inserts bv.) kun je 'm in 1 keer de tabel in de database bij laten werken.

En zo zijn er nog wel meer mogelijkheden. Ik gebruik zelf meestal een eigengeschreven O/R mapping systeempje, maar dat gaat hier denk ik ietsje te ver...

  • JoostMartijn
  • Registratie: December 2003
  • Laatst online: 17-04-2025
Ik gebruik geen complete SQL query's omdat hetzelfde effect heeft. Plus het feit dat de INSERT query's dan te lang kunnen worden met het risco dat de STRING EOF(end of File) wordt.

Ik zal het testen met een ClientDataSet.

Windsoft


Verwijderd

Dat een TQuery met RequestLive=True net zo traag is, is wel logisch. De manier waarmee BDE/DBExpress/ADO daarmee omgaat is nl. vrijwel identiek aan een TTable.

Je mag overigens ook wel 300x achter elkaar een TQuery.ExecSQL uitvoeren hoor, als je maar niet na iedere keer de data weer opnieuw fetcht.

  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 15:16

Tomatoman

Fulltime prutser

JoostMartijn schreef op donderdag 07 juli 2005 @ 15:13:
Ik gebruik geen complete SQL query's omdat hetzelfde effect heeft. Plus het feit dat de INSERT query's dan te lang kunnen worden met het risco dat de STRING EOF(end of File) wordt.

Ik zal het testen met een ClientDataSet.
Drie keer raden hoe een TTable een record toevoegt :z

Een goede grap mag vrienden kosten.


  • JoostMartijn
  • Registratie: December 2003
  • Laatst online: 17-04-2025
Aan de tabel hangt geen grid of iets dergelijks zelfs geen Datasource. Ik doe DisableControls voor de betreffende tabel. Maar nog steeds gaat het langzaam met insertRecord of Append record. Voor zover ik kan na gaan wordt er geen data gefetched.

Ik zal het nu met een ClientdataSet proberen en dan die (tijdelijke)tabel in één keer proberen te schrijven. Ik hoop dat ik zo het probleem omzeil :) .

Windsoft


  • Robbemans
  • Registratie: November 2003
  • Laatst online: 17-07-2025
Wat hangt er op databaseniveau allemaal aan je tabel? Triggers, indexen, transacties, van alles kan vertragend werken... Staar je niet alleen blind op de tabel.

  • JoostMartijn
  • Registratie: December 2003
  • Laatst online: 17-04-2025
Ik heb net begonnen met de bouw van de applicatie. Aan de database kant zit nog niks. Geen triggers of wat dan ook. Zelfs geen triggers voor auto nummering. De hele database bestaat maar uit 5 tabelen.

Maar zijn jullie het met mij eens dat 5 a 10 vrij lang is voor 300 records?

Windsoft


  • Robbemans
  • Registratie: November 2003
  • Laatst online: 17-07-2025
JoostMartijn schreef op vrijdag 08 juli 2005 @ 09:43:
Maar zijn jullie het met mij eens dat 5 a 10 vrij lang is voor 300 records?
Ja en nee. 300 x een insert mag best 5 seconden duren. Erg gebeurt nogal wat natuurlijk voordat een record in een database zit (intern).

Echter, als het een kale insert aan de serverkant is, dan is dit vrij langzaam. De grote vraag blijft nog steeds hoe je precies de records in de database propt.

Heb je dit al met de ClientDataSet geprobeerd (ApplyUpdates) en die getimed? Dat zijn in principe kale posts, die in principe snel kunnen worden afgehandeld.

Verwijderd

Vergeet ook niet dat als je het uitlezen van data heel snel maakt door bv extra indexen het inserten, appenden een stuk trager kan worden doordat de insert ook de indexen moet bijwerken. Daar zul je dus altijd een tradeoff hebben.

Maar in Delphi is het altijd het snelste om
1) met eigen SQL te werken (client datasets genereren uiteindelijk ook SQL)
2) binnen je SQL altijd met parameters te werken
3) SQL queries te hergebruiken

Dus iets van (uit het hoofd dus het zal wel niet werken)
code:
1
2
3
4
5
6
7
8
9
10
11
12
  with TQuery.Create(self) do
  begin
     SQL.Clear;
     SQL.Add("INSERT INTO DATATABEL (kolom1,kolom2) values (:Kolom1.:Kolom2) ");
     params.parambyname("kolum1").asString="test";
     params.parambyname("kolum2").asinteger=123;
     execSQL;
     params.parambyname("kolum1").asString="test2";
     params.parambyname("kolum2").asinteger=1234;
     execSQL;
     Free;
  end;


Wat je ook kan proberen is de TTable (of TQuery) in batchmode te zetten en een commitupdates te doen en tot slot hangt het ook nog af van welke database componenten je gebruikt in combinatie met welke database. Niet alle combinaties zijn namelijk even optimaal.

  • paulh
  • Registratie: Juli 1999
  • Laatst online: 12-03 16:31
Je moet het wel binnen een transactie doen. En daarna pas de commit.
Dat scheelt vaak ook heel veel tijd. Anders zit je ook nog 300 commits te doen.

[ZwareMetalen.com] - [Kom in aktie tegen de CO2 maffia]


  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 15:16

Tomatoman

Fulltime prutser

Verwijderd schreef op zaterdag 09 juli 2005 @ 02:24:
Maar in Delphi is het altijd het snelste om
[..]
3) SQL queries te hergebruiken
Dat is waar, maar...
Dus iets van (uit het hoofd dus het zal wel niet werken)
code:
1
2
3
4
5
6
7
8
9
10
11
12
  with TQuery.Create(self) do
  begin
     SQL.Clear;
     SQL.Add("INSERT INTO DATATABEL (kolom1,kolom2) values (:Kolom1.:Kolom2) ");
     params.parambyname("kolum1").asString="test";
     params.parambyname("kolum2").asinteger=123;
     execSQL;
     params.parambyname("kolum1").asString="test2";
     params.parambyname("kolum2").asinteger=1234;
     execSQL;
     Free;
  end;
...dat hoor je NIET te doen zoals in dit vorbeeld. Bij hergebruik van een query haal je de winst, doordat een query die je opnieuw uitvoert al prepared is. Daarvoor moet je echter wel Prepare aanroepen, omdat dat anders impliciet gebeurt en er direct na het uitvoeren van de query een impliciete Unprepare wordt uitgevoerd. Bovendien heeft de code een potentieel geheugenlek, omdat er geen finally blok rond Free staat.

Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
with TQuery.Create(Self) do
try
  Connection := MijnConnection;
  SQL.Text := 'INSERT INTO Datatabel (Kolom1, Kolom2) ' +
    'VALUES (:Kolom1, :Kolom2)';
  Prepare;
  Params.ParamByName('Kolom1').AsString := 'test';
  Params.ParamByName('Kolom2').AsInteger := 123;
  ExecSQL;
  Params.ParamByName('Kolom1').AsString := 'test2';
  Params.ParamByName('Kolom2').AsInteger := 1234;
  ExecSQL;
  Unprepare;
finally
  Free;
end;
Maar dat laat onverlet dat Jan Klaasen een aantal heel zinnige opmerkingen maakt. :)

[ Voor 9% gewijzigd door Tomatoman op 09-07-2005 12:28 ]

Een goede grap mag vrienden kosten.


  • JoostMartijn
  • Registratie: December 2003
  • Laatst online: 17-04-2025
Het gaat het snelste als er gebruik wordt gemaakt van een ClientdataSet _/-\o_ . Hij leest dan 300 records in een paar ms. Het vliegt er door heen. Ben nu alleen nog op zoek naar een manier op de clientdataset in 1x in de database te zetten!

Heeft iemand een idee hoe dit het beste kan? Snel en netjes?

Windsoft


  • alienfruit
  • Registratie: Maart 2003
  • Laatst online: 11:08

alienfruit

the alien you never expected

Misschien heb je wat aan dit artikel van Bob Swart?
http://www.drbob42.com/delphi5/examin64.htm

[ Voor 58% gewijzigd door alienfruit op 21-07-2005 10:54 ]


  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 15:47

Creepy

Tactical Espionage Splatterer

Je clientdataset kan je aan je tabel linken he ;)
Overigens doet ee CLientDataset alles (!) in memory. Pas als je een ApplyUpdates geeft zal ie daadwerkelijk alles in de DB wegschrijven.

Je kan volgens mij ook tegen een ttable zeggen dat je gaat updaten zodat ie zichzelf niet elke keer weer opnieuw ververst.
code:
1
2
3
Table1.BeginUpdate;
// 300 keer een Table1.Append 
Table1.EndUpdate

Ik heb hier ff zo snel geen Delphi bij de hand dus check dat ff voor de zekerheid.

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


  • JoostMartijn
  • Registratie: December 2003
  • Laatst online: 17-04-2025
Hoe kan ik de clientdataset aan een tabel linken dan? Gaat dat via de master source of via een dataSource. Zit al de heledag op internet te zoeken maar dat is slecht gedocumenteerd?

Windsoft


  • alienfruit
  • Registratie: Maart 2003
  • Laatst online: 11:08

alienfruit

the alien you never expected

TDataSetProvider ofzo ? Die knopt een TDataSet aan een TClientDataSet dan kan je vast ook wel de andere kant op. Ik heb hier ook niet Delphi opstaan dus ik kan niet voor je kijken.

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 15:47

Creepy

Tactical Espionage Splatterer

JoostMartijn schreef op donderdag 21 juli 2005 @ 16:28:
Hoe kan ik de clientdataset aan een tabel linken dan? Gaat dat via de master source of via een dataSource. Zit al de heledag op internet te zoeken maar dat is slecht gedocumenteerd?
Help -> Delphi Help -> TClientDataset -> Using TClientDataSet -> Using a client dataset to cache updates.
Slecht gedocumenteerd zeg je? ;)

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney

Pagina: 1