AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Datenbanken Vergleich Firebird: C# vs. Delphi Win32
Thema durchsuchen
Ansicht
Themen-Optionen

Vergleich Firebird: C# vs. Delphi Win32

Ein Thema von Morphie · begonnen am 22. Sep 2011 · letzter Beitrag vom 23. Sep 2011
Antwort Antwort
Seite 1 von 2  1 2      
Morphie

Registriert seit: 27. Apr 2008
Ort: Rahden
630 Beiträge
 
#1

Vergleich Firebird: C# vs. Delphi Win32

  Alt 22. Sep 2011, 15:00
Datenbank: Firebird • Version: 2.5 • Zugriff über: ADO.NET / IBDAC
Hi, ich lerne gerade C# und wollte einen Datenimport für Firebird programmieren.
Leider musste ich feststellen, dass meine C#-Lösung ca. 8x langsamer ist als meine Delphi-Lösung.

Habt ihr eine Idee, was ich hier falsch mache?

Habe mal ein Beispielprojekt gemacht.

Delphi-Code:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  Con: TIBCConnection;
  Qry: TIBCQuery;
  i: integer;
const
  max = 10000;
begin
  Con := TIBCConnection.Create(nil);
  try

    Con.Server := 'localhost';
    Con.Username := 'SYSDBA';
    Con.Password := 'masterkey';
    Con.Database := 'F:\Test.fdb';
    Con.Open;

    Qry := TIBCQuery.Create(nil);
    try
      Qry.Connection := Con;
      Qry.Params.CreateParam(ftInteger,'Par1',ptInput);
      Qry.Params.CreateParam(ftFloat,'Par2',ptInput);
      Qry.Params.CreateParam(ftString,'Par3',ptInput);
      Qry.Params.CreateParam(ftDateTime,'Par4',ptInput);
      Qry.SQL.Text := 'UPDATE OR INSERT INTO TEST (FELD1, FELD2, FELD3, FELD4) VALUES (:Par1, :Par2, :Par3, :Par4);';
      Qry.Prepare;

      ProgressBar1.Max := max;
      ProgressBar1.Position := 0;

      for i := 0 to max do
      begin
        Qry.ParamByName('Par1').Value := i;
        Qry.ParamByName('Par2').Value := i;
        Qry.ParamByName('Par3').Value := 'Test';
        Qry.ParamByName('Par4').Value := Now;
        Qry.Execute;

        ProgressBar1.Position := i;
        Label1.Caption := inttostr(i) + ' / ' + inttostr(max);
        Application.ProcessMessages;
      end;

    finally
      qry.Free;
    end;

  finally
    Con.Free;
  end;
end;
C#-Code:
Code:
private void button2_Click(object sender, EventArgs e)
{
    FbConnection Con = new FbConnection();
    FbConnectionStringBuilder ConStrBuilder = new FbConnectionStringBuilder();

    // ConnectionString bauen
    ConStrBuilder.DataSource = "localhost";
    ConStrBuilder.UserID = "SYSDBA";
    ConStrBuilder.Password = "masterkey";
    ConStrBuilder.Database = "F:\\Test.fdb";
               
    // ConnectionString zuweisen
    Con.ConnectionString = ConStrBuilder.ConnectionString;
    Con.Open();

    FbCommand Cmd = new FbCommand();
    Cmd.Connection = Con;
    Cmd.Parameters.Add("Par1", FbDbType.Integer);
    Cmd.Parameters.Add("Par2", FbDbType.Decimal);
    Cmd.Parameters.Add("Par3", FbDbType.VarChar);
    Cmd.Parameters.Add("Par4", FbDbType.TimeStamp);
    Cmd.CommandText = "UPDATE OR INSERT INTO TEST (FELD1, FELD2, FELD3, FELD4) VALUES (@Par1, @Par2, @Par3, @Par4);";
    Cmd.Prepare();

    const int max = 10000;

    progressBar1.Maximum = max;
    progressBar1.Value = 0;

    for (int i = 0; i < max; i++)
    {
        Cmd.Parameters["Par1"].Value = i;
        Cmd.Parameters["Par2"].Value = i;
        Cmd.Parameters["Par3"].Value = "Test";
        Cmd.Parameters["Par4"].Value = DateTime.Now;
        Cmd.ExecuteNonQuery();

        progressBar1.Value = i;
        label2.Text = i.ToString() + " / " + max.ToString();
        Application.DoEvents();
    }
}
Ich habe auch schon Transaktionen eingebaut, das hat allerdings auch nichts gebracht.

Die Tabellendefinition sieht so aus:
Code:
CREATE TABLE TEST (
  FELD1  INTEGER NOT NULL,
  FELD2  DECIMAL,
  FELD3  VARCHAR(20),
  FELD4  TIMESTAMP,
  /* Schlüssel */
  PRIMARY KEY (FELD1)
);
Folgende Werte konnt ich mittels GetTickCount (sind das eig. Millisekunden?) ermitteln:
Code:
Versuch   Delphi   C#
1          8515      68312
2          8297      55312
3          8703      54969
4          9984      53969
5          8671      54218

Geändert von Morphie (22. Sep 2011 um 15:02 Uhr)
  Mit Zitat antworten Zitat
Elvis

Registriert seit: 25. Nov 2005
Ort: München
1.909 Beiträge
 
Delphi 2010 Professional
 
#2

AW: Vergleich Firebird: C# vs. Delphi Win32

  Alt 22. Sep 2011, 15:08
Das DoEvents muss in Winforms mehr machen, als in Delphi.
Hat da auch gar nix zu suchen. In Winforms kannst du den BackgroundWorker nehmen wenn du ohne viel Arbeit etwas im Hintergund erledigen willst.
DoEvents ist nur dafür da um WinForms zu zwingen JETZT die MessageQueue abzuarbeiten, aber nicht um die UI bedienbar zu machen.
So schnell wie in Delphi kann das aber nicht werden. Denn der firebird Client ist eine native DLL, und Calls in native DLLs müssen ihre Daten ständig von & zu .Net übersetzen. Das kostet einfach ein bissel was.

Wenn du mehr zu Threading in C# wissen willst, schaue die die TPL an.
Robert Giesecke
I’m a great believer in “Occam’s Razor,” the principle which says:
“If you say something complicated, I’ll slit your throat.”
  Mit Zitat antworten Zitat
Morphie

Registriert seit: 27. Apr 2008
Ort: Rahden
630 Beiträge
 
#3

AW: Vergleich Firebird: C# vs. Delphi Win32

  Alt 22. Sep 2011, 15:17
Oh, habe vergessen zu sagen, dass das DoEvents bzw. ProcessMessages erst später dazu kam, um die Anzeige zu aktualisieren. Es macht also keinen großen Unterschied ob mit oder ohne DoEvents.
Ist ja auch nur ein Beispielprogramm...
Dass DoEvents gar nicht benötigt wird, wusste ich nicht. Tut einfach so als wäre es nich da
  Mit Zitat antworten Zitat
tsteinmaurer

Registriert seit: 8. Sep 2008
Ort: Linz, Österreich
530 Beiträge
 
#4

AW: Vergleich Firebird: C# vs. Delphi Win32

  Alt 22. Sep 2011, 15:23
Weil du Transaktionen erwähnt hast. War das eine explizit gestartete Transaktion, in der dann alles lief? Weil deine Beispiele sehen nach AutoCommit-Modus aus, d.h. nach jedem Query-Execute wird ein Commit(Retaining) gemacht.
  Mit Zitat antworten Zitat
Morphie

Registriert seit: 27. Apr 2008
Ort: Rahden
630 Beiträge
 
#5

AW: Vergleich Firebird: C# vs. Delphi Win32

  Alt 22. Sep 2011, 15:36
Eine Transaktion die explizit gestartet wird:
Code:
private void button2_Click(object sender, EventArgs e)
{
    FbConnection Con = new FbConnection();
    FbConnectionStringBuilder ConStrBuilder = new FbConnectionStringBuilder();

    // ConnectionString bauen
    ConStrBuilder.DataSource = "localhost";
    ConStrBuilder.UserID = "SYSDBA";
    ConStrBuilder.Password = "masterkey";
    ConStrBuilder.Database = "F:\\Test.fdb";
               
    // ConnectionString zuweisen
    Con.ConnectionString = ConStrBuilder.ConnectionString;
    Con.Open();

    FbTransaction Trans = Con.BeginTransaction();

    FbCommand Cmd = new FbCommand();
    Cmd.Connection = Con;
    Cmd.Transaction = Trans;
    Cmd.Parameters.Add("Par1", FbDbType.Integer);
    Cmd.Parameters.Add("Par2", FbDbType.Decimal);
    Cmd.Parameters.Add("Par3", FbDbType.VarChar);
    Cmd.Parameters.Add("Par4", FbDbType.TimeStamp);
    Cmd.CommandText = "UPDATE OR INSERT INTO TEST (FELD1, FELD2, FELD3, FELD4) VALUES (@Par1, @Par2, @Par3, @Par4);";
    Cmd.Prepare();

    const int max = 5000;

    progressBar1.Maximum = max;
    progressBar1.Value = 0;

    for (int i = 0; i < max; i++)
    {
        Cmd.Parameters["Par1"].Value = i;
        Cmd.Parameters["Par2"].Value = i;
        Cmd.Parameters["Par3"].Value = "Test";
        Cmd.Parameters["Par4"].Value = DateTime.Now;
        Cmd.ExecuteNonQuery();

        progressBar1.Value = i;
        label2.Text = i.ToString() + " / " + max.ToString();
        Application.DoEvents();
    }
    Trans.Commit();
}
  Mit Zitat antworten Zitat
Benutzerbild von Phoenix
Phoenix
(Moderator)

Registriert seit: 25. Jun 2002
Ort: Hausach
7.640 Beiträge
 
#6

AW: Vergleich Firebird: C# vs. Delphi Win32

  Alt 22. Sep 2011, 15:38
Folgende Werte konnt ich mittels GetTickCount (sind das eig. Millisekunden?) ermitteln:
Erm.. du bist da ein wenig off in .NET:
Zitat von MSDN:
A single tick represents one hundred nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond.
Das heisst das ganze Ding braucht da ca. 5,5 Sekunden. Das ist tatsächlich ziemlich langsam für nur 10.000 inserts.
Sebastian Gingter
Phoenix - 不死鳥, Microsoft MVP, Rettungshundeführer
Über mich: Sebastian Gingter @ Thinktecture Mein Blog: https://gingter.org

Geändert von Phoenix (22. Sep 2011 um 15:41 Uhr)
  Mit Zitat antworten Zitat
Morphie

Registriert seit: 27. Apr 2008
Ort: Rahden
630 Beiträge
 
#7

AW: Vergleich Firebird: C# vs. Delphi Win32

  Alt 22. Sep 2011, 15:49
Das heisst das ganze Ding braucht da ca. 5,5 Sekunden. Das ist tatsächlich ziemlich langsam für nur 10.000 inserts.
Habe mal mitgezählt. Es sind 50 Sekunden bei 5000 Datensätze!?
  Mit Zitat antworten Zitat
Benutzerbild von Phoenix
Phoenix
(Moderator)

Registriert seit: 25. Jun 2002
Ort: Hausach
7.640 Beiträge
 
#8

AW: Vergleich Firebird: C# vs. Delphi Win32

  Alt 22. Sep 2011, 15:58
Vergiss das mitzählen.
Nimm eine Stopwatch, die ist genau für solche Zeitmessungen da und ist dafür sehr exakt.

Erstmal eine komplett drumrum.

Dann am besten zwei Stopwatches:
Die eine ums komplette rum, die zweite stoppst Du in jedem Durchlauf, schreibst die elapsed time z.B. in eine List<TimeSpan>, resettest und startest sie neu.

Dann hast Du auch ne Info wie lange ein insert dauert.
Du kannst auch alternativ während die Stopwatch läuft ab und zu die elapsed time auslesen und z.B: auf die Debug- oder Trace-Klasse schreiben.
Dann siehst Du am ehesten bei welchen calls die meiste Zeit verloren geht.

Aber aufpassen: Wenn Du das im Debug-Build und im worst case noch mit attachtem debugger laufen lässt wird das dann *richtig* langsam.
Sebastian Gingter
Phoenix - 不死鳥, Microsoft MVP, Rettungshundeführer
Über mich: Sebastian Gingter @ Thinktecture Mein Blog: https://gingter.org
  Mit Zitat antworten Zitat
Satty67

Registriert seit: 24. Feb 2007
Ort: Baden
1.566 Beiträge
 
Delphi 2007 Professional
 
#9

AW: Vergleich Firebird: C# vs. Delphi Win32

  Alt 22. Sep 2011, 17:31
im worst case noch mit attachtem debugger laufen lässt wird das dann *richtig* langsam.
...oder anders ausgedrückt Zeitmessung mit Strg-F5 (statt F5)

Morphies Beispiel-Code ist bei mir ohne Debugger ziemlich genau um den Faktor 8 schneller.

(ohne string + string + string und DoEvents bei jedem Durchlauf sollte es vergleichbar schnell wie mit Delphi sein)
  Mit Zitat antworten Zitat
Benutzerbild von Phoenix
Phoenix
(Moderator)

Registriert seit: 25. Jun 2002
Ort: Hausach
7.640 Beiträge
 
#10

AW: Vergleich Firebird: C# vs. Delphi Win32

  Alt 22. Sep 2011, 19:58
Morphies Beispiel-Code ist bei mir ohne Debugger ziemlich genau um den Faktor 8 schneller.

(ohne string + string + string und DoEvents bei jedem Durchlauf sollte es vergleichbar schnell wie mit Delphi sein)
Naja, das
Code:
label2.Text = i.ToString() + " / " + max.ToString();
ist eine einzige Konkatenation und erzeugt lediglich eine neue String-Variable. Das sollte verschmerzbar sein und nicht stören. Am besten packt er das ganze in einen Background-Thread (wurde schon angesprochen), die Label - Aktualisierung dann in eine jeweils neue anonyme Methode und schmeisst die dann zum Invoken auf den Mainthread. So hat die DB-Geschichte einen kompletten Kern für sich und das UI darf versuchen hinter den ganzen Aktualisierungen herzulaufen
Sebastian Gingter
Phoenix - 不死鳥, Microsoft MVP, Rettungshundeführer
Über mich: Sebastian Gingter @ Thinktecture Mein Blog: https://gingter.org
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:39 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz