Was ist von der Geschwindigkeit her besser?

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 33 Antworten in diesem Thema. Der letzte Beitrag () ist von EugenIS.

    Was ist von der Geschwindigkeit her besser?

    Hallo Leute und danke fürs reinschauen...

    angenommen, ich benötige eine Datenbank-Verbindung. Was wäre besser einen Globalen Pool zu erstellen, wo jede Klasse eine raus nimmt, benutzt und wieder zurück gibt, oder ein using(...) zu benutzen?

    Was wisst/denkt ihr drüber?
    @EugenIS Wie oft greifst Du denn auf die DB zu?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    EugenIS schrieb:

    was passiert bei der async zugriffweise...
    Datenbanken sind üblicherweise Thread-Safe, da sollte das egal sein.
    Wenn Du allerdings einen zentralen DB-Zugriff hast, kannst Du ggf. nicht async drauf zugreifen.
    Ich hatte mal einst ein kleineres DB-Projekt, da wurde alles mit Using gemacht, das würde ich heute genau so machen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Die Datenbankverbindungen sind sowieso gepoolt, alles was den gleichen ConnectionString hat ist der selbe Pool. D.h. wenn du eine Verbindung mit Dispose freigibst, ist nicht die Verbindung weg.

    docs.microsoft.com/en-us/dotne…server-connection-pooling

    Siehe 1. und 2. Antwort

    stackoverflow.com/questions/5244126/net-connection-pooling
    ich benutze eigentlich bevorzugt die Entities... Demnach sieht es dann so aus:

    C#-Quellcode

    1. ​try
    2. {
    3. using (var tmpCon = new wmSysEntities())
    4. tmpCon.Database.ExecuteSqlCommand("INSERT INTO [wmSys].[tSqlProto] VALUES ({0}, CURRENT_TIMESTAMP, {1}, {2}, -1, {3})", wm00_GlobalHelper.pcName, tmpTimer.Elapsed.TotalMilliseconds.ToString().Replace(',', '.'), string.Format(sql, parameters), e.Message);
    5. }
    6. ...


    Habe recht gute Erfahrungen mit gemacht... Na gut, benutze ich das vorerst weiterhin so wie gehabt...

    Danke euch allen....

    EugenIS schrieb:

    was passiert bei der async zugriffweise...

    Nix, klappt hervorragend. Mach ich des öfteren und hatte bis dato noch nie Probleme damit.
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen
    Hallo

    Sorry das ich mich hier einmische. Das sieht mir fast nach EntityFramework aus was @EugenIS hier verwendet.
    In diesem Fall MUSS/SOLLTE es mit einem UsingBlock verwendet werden das alles andere beim EF zu sehr merkwürdigen verhalten führen kann. Nur so als Tipp falls es wirklich EF sein sollte.
    PS: Ich frage mich warum man mit EF ExecuteSqlCommand für solch ein Insert verwendet?

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Ja mag sein, normalerweise.
    Aber ich gehe davon aus, dass Eugen das EF vollkommen unnormal verwendet, nämlich nicht für Linq2Sql und als Cache abgerufener DAten, sondern nur als "Raw-Sql-Submitter", also zum absetzen selbstgebastelten Sqls. Und da hätte ich gedacht, dass dabei der EF-Cache nicht vollläuft.

    (Übrigens finde ich's recht jämmerlich vom EF, dasses quasi ein "MemoryLeak by Design" eingebaut hat.

    Aber ich bin auch nicht sicher, ob das tatsächlich das Problem ist, oder ein anneres - vlt. weisst du da mehr?

    Findich eine hochinteressante Frage: Warum darf man EF-Contexte nicht aufheben, so lang man will? Ich hab damals bisserl danach recherchiert, bin aber nur immer wieder auf dieses stereotype Dogma gestossen - nie auf eine Begründung.
    Die ich mir jetzt selbst zusammenreime, nämlich: Beim Datenbezug via EF-Context wird Speicher belegt, und es existiert kein Mechanismus, den wieder vollständig freizugeben - ausser eben .Dispose, den ganzen Context wegwerfen.
    /OffTopic
    )
    Hallo

    Naja, doch, du kannst schon den Cache leeren und den speicher freigeben. Einfach alle Entitäten "Detachen". DetachAll() für die Contextinstanz.
    Man kann es auch nicht als MemoryLeak sehen da dieses Verhalten ja gewollt ist!! Its not a bug, its a feature!!

    Warum? EF ist im stande Entitäten welche bereits geladen wurden unter Umständen aus dem Cache zu holen. Z.b. macht die Methode Find genau das. Hier wird im Cache nachgesehen ob die Enität mit der ID bereits im Cache vorhanden ist und verwendet anschliessend die aus dem Cache, ansonsten wird ein Select abgesetzt.

    Der Grund warum der Context nicht "offen" bleiben soll ist aber ein anderer. Und zwar schon aus dem Grund weil der Context NICHT Treadsafe ist. Das ist auch überall nachlesbar. Und cih habe schnell mal etwas Async laufen und handle mir hier enorme probleme ein. Diese habe ich nicht wenn ich mit einem Usingblock arbeite. Denn ich kann schon mehrere Contextinstanzen gleichzeitig offen haben und mit diesen auch paralell Daten abrufen.
    Außerdem kann es beim Verwenden von ein und der selben Instanz eines Context zu enormen problemen mit dem Changetracker kommen. Ohne jetzt zu sehr ins Detail zu gehen muss ich leider sagen. Bitte Arbeitet mit EF immer mit Using, ihr spart euch probleme und unangenehme Nebeneffekte.

    Ich hoffe ich habe alle Punkte soweit klargestellt ansonsten beantworte ich gerne aufkommende Fragen so gut ich kann, bin ja jetzt auch nicht der EF Guru aber ich arbeite bereits länger damit seit der 4.0 des alten Frameworks.

    Zu meinem Vorigen Beitrag vieleicht noch. Sobald ich mal einen SQL selbst schreibe anstatt LinqToEntities (nicht mit LingToSQL zu verwechseln) verliere ich viele tolle Features des EF wie z.b. das ich jederzeit einen anderen Datenbankprovider verwenden kann wenn ich oder der Kunde das möchte ohne neu kompilieren zu müssen. Für viele nicht wirchtig aber mann sollte es bedenken. 8o

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    naja, dasser nicht threadsafe ist - ok - arbeitet man mit Nebenläufigkeiten, dann ist das wichtig.
    Sollte imo aber kein zwingender grund sein, immer mit using zu arbeiten.
    Alle anneren Auflistungen (ausser speziell auf threading ausgelegte) sind ebensowenig threadsafe - bei Nebenläufigkeit muss man halt wissen, was man tut.
    Ich zB würde sowieso dafür sorgen, dass wenn der eine Datenabruf async läuft, dass der User dann keinesfalls (nebenläufig!) einen 2. Abruf starten kann.
    Ist ja logisch, dass solch ganz schnell kuddelmuddelt, ob nu mit oder ohne using - wie gesagt: bei Nebenläufigkeit muss man wissen, was man tut.

    Das mit dem ChangeTracker mag ich kaum glauben..
    Heisst das, wenn ich mw. Artikel in einen Context lade, und danach noch Kunden, dass EF dann das ChangeTracking nicht mehr zuverlässig gebacken bekommt?
    Da wäre EF ja miserabler als ich gedacht habe.



    Nofear23m schrieb:

    (nicht mit LingToSQL zu verwechseln)
    ähm - von dem her was da vorgeht, ist Linq2Entities Linq2Sql - weil kommt ja Sql hinten raus.



    Nofear23m schrieb:

    Zu meinem Vorigen Beitrag vieleicht noch. Sobald ich mal einen SQL selbst schreibe anstatt LinqToEntities [...] verliere ich viele tolle Features des EF wie z.b...
    Naja, das dollste Feature ist ja, dass man intellisense-gestützt typisierte Objekte vonne Db abfragt, und nicht "String-Smells" produziert, und sich hinterher ums Mapping auf typ.Objekte selber kümmern muss.
    (Zumindest inne Theorie.
    Praktisch ists ja oft so, dass man die EF-Objekte dann doch nochmal umfüllt in ein selbstgebasteltes Datenmodell, was ja auch Mapping ist. Und ChangeTracking ist damit auch so einigermassen beim Deibel, es sei denn, man legt da auch nochmal extra Hand an.)

    Wie dem auch sei
    Türlich ist Linq2Sql/Entities dem StringSmell-Gebastel vorzuziehen, wg Intellisense und Syntax-Sicherheit.
    Hallo

    ErfinderDesRades schrieb:

    Das mit dem ChangeTracker mag ich kaum glauben..
    Heisst das, wenn ich mw. Artikel in einen Context lade, und danach noch Kunden, dass EF dann das ChangeTracking nicht mehr zuverlässig gebacken bekommt?
    Da wäre EF ja miserabler als ich gedacht habe.

    Da hast du mich falsch verstanden. Das kann er alles. Jedoch! Rufe ich den Datensatz mit der ID 5 ab und benötige hier nur ein oder zwei Properties werden auch nur diese spalten abgerufen und sind im Cache.
    Jetzt schau ich im Cache nach und will eine ganz andere spalte. Die wird aber nicht befüllt sein. Ich denke nur nicht daran weil ich die Entität an einer ganz anderen stelle abgerufen hatte. Das meinte ich.
    Ist nur ein Beispiel, es kann hier sehr viele probleme geben. Auch konflikte kann es geben, Insbesonders wenn ich dann vieleicht sogar wie der TE mit SQL Strings arbeite.

    ErfinderDesRades schrieb:

    ähm - von dem her was da vorgeht, ist Linq2Entities Linq2Sql - weil kommt ja Sql hinten raus.

    Im endeffekt ja, dennoch ist es LinqToEntity. Ich erhalte Entitäten und arbeite innerhalb des Linq mit Entitäten. War ja auch nur ein kleiner Hinweis, bitte nicht immer persönlich nehmen.

    Zu deinem Threadsafe/Async Anmerkung.
    Klar kann man versuchen immer darauf zu achten das man nicht an zwei stellen gleichzeitig abruft. Aber... ernsthaft. Warum die Arbeit antun.
    Ich habe aktuell in einer Anwendung im Hauptmenster eine Userliste welche sich all 30 Sekunden aktualisiert und zeigt welche User Online und welche Online sind.
    Ich müsste als dann bei JEDEM zugriff auf EF vorher prüfen bzw. die aktuelisierung der Userliste "blockieren" und sicherzustellen das mir das ganze nicht um die Ohren fliegt.

    Das ist alles andere als schön. Arbeite ich entweder mit Using oder Dispose ich immer brav erledigt sich das von selbst.

    PS: EF Core ab 2.1 unterstützT auch Pooling. Man kann nun eine Instanz "benennen" und diese später wiederverwenden. Nur so als Info.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Nofear23m schrieb:

    Zu deinem Threadsafe/Async Anmerkung.
    Klar kann man versuchen immer darauf zu achten...
    Hat nix mit "versuchen" zu tun, sondern ist einfach MustDo-So-oder-so.

    Nofear23m schrieb:

    Aber... ernsthaft. Warum die Arbeit antun.
    Naja - manchmal kann man ganz schön was optimieren, wenn man etwas wiederverwendet, anstatt es immer komplet wegzuwerfen und neu zu instanzieren.
    Solch wäre ein Grund, "sich die Arbeit anzutun" - und ist oft auch garnet Mehr-Arbeit sondern nur eine Frage der Architektur.

    So ganz generell - hat jetzt nix mit EF-Context zu tun.
    (Naja - der Thread-Titel fragt schon nach Optimierung...)

    Also von wegen Optimierung: MIt EF geht da glaub nix - ich hab tatsächlich mal selbstfrickel-Sql verglichen mit Linq2Sql ( :P ), und fund keinen nennenswerten Performance-Unterschied.
    Nicht getestet habich die Kosten der ständigen disposerei/re-instanzierung.
    Da weiss ich echt nicht. Man sagt ja, eine DbConnection zu etablieren ist bei Winz-Abfragen ein deutlicher Zeitfaktor. Und diese EF-Contexte sind intern möglicherweise auch ganz schöne Monstrositäten.
    Aber vlt auch nicht, wie gesagt, getestet habich nicht, weil bei uns auf Arbeit gabs zum Using erstma keine Alternative.
    Hallo

    Also zum Thema Performance kann man bei EF Core (ich rede wirklich von Core denn da hat sich ENORM was bei der Performance getan) wirklich viel rausholen wenn man es richtig anwendet.
    Im NoTracking Mode ist z.b. EF Core fast genauso schnell wie ADO.Net mit manuellem Mapping. So viel "Monstrositäten" wie in EF 6 sind da jetzt nicht mehr vorhanden. EF 6 war da leider anders.
    Ich rede hier von unterschieden im wenigen Millisekunden-Bereich beim Abrufen von 1000 Datensätzen.

    Aber gut, das soll jetzt nicht in diesen Thread. Fakt ist und da kann ich den Entwicklern von EF und der Doku nur zustimmen, man bekommt hier und da unschöne Nebeneffekte wenn man den Context immer wieder verwendet. Vorallem... ist ja gar nicht notwendig. Ich Dispose und fertich. Kann jeder anders Handhaben, wenn hier jemand dann aber eine Frage stellt und er wendet EF nicht korrekt an dann wirds von mir eine am Deckel geben und er darf dies mal korrigieren damit ich (wir) dies als Fehler mal ausschliessen können. Also gleich so verwenden wie von den Entwicklern gewollt. ICh fahre ja auch nicht mit nem Smart die Rally Dakar mit und frage mich dann warum ich nicht mal die erste Etappe schaffe. 8-)

    OK, und nun BackToTopic please.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    ​PS: Ich frage mich warum man mit EF ExecuteSqlCommand für solch ein Insert verwendet?


    nun ja, um auf die Frage zurück zu kommen... Testet es selbst was von der Geschwindigkeit besser ist... ExecuteSqlCommand ladet nicht die ganze Tabelle hoch. Somit ist es wesentlich schneller... Oder ich habe damals was falsch gemacht... Für Büro-Zwecke wird es vermutlich ausreichen per Entity es zu machen wie sich das gehört. In Maschinenbereich ist es schon echt zu langsam und überhaupt nicht geeignet...
    OK, ich greife es jetzt nochmal auf.

    Was meinst du mit "ganze Tabelle" - nicht das wir aneinander vorbeireden. Du meinst vermutlich "alle Spalten". Also wenn du 5 Spalten hast und du änderst einen Wert in Spalte 3 dann aktualisiert EF alle Spalten obwohl sich die Werte in den anderen vier Spalten nicht geändert haben? Richtig?

    Das liegt dann aber daran das du den ChangeTracker falsch verwendest und EF es somit nicht besser weis. Du sagst es EF ja vermutlich mit sowas wie entität.State = Changed oder Attached diese vieleicht sogar händisch.
    Dann ist es logisch, du sagst EF ja das sich der Datensatz geändert hat.
    Zwei Möglichkeiten: Du sagst EF das sich nur ein Property geändert hat db.Entry(model).Property(Function(x) x.MyProp).IsModified = True oder du arbeitest einfach mit Tracking und lässt EF seine arbeit verrichten.
    Meisst ist es so das die Leute EF schlicht falsch verwenden und sich dann wundern. Hier ist es aber eine schlechte Idee dann einfach auf ExecuteSQL auszuweichen. Ist nur gut gemeint.

    Ob du dich mit EF beschäftigst und dir in Zukunft viel ärger ersparst bleibt dir selbst überlassen, ich kann dir nur den Rat geben.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    also zu seiner Zeit habe ich damit hier experementiert:

    entityframeworktutorial.net/cr…rio-entity-framework.aspx

    und das was so langsam, jedenfalls nach meinem Verständnis, dass ich doch dann wieder auf sowas hier umgestiegen bin:

    C-Quellcode

    1. ​using (var context = new SchoolDBEntities())
    2. context.Database.SqlQuery<...>("Select...").FirstOr...()


    Jedes mal wenn ich das mit einer StopUhr (Stopwatch) getestet habe, hat es wesentlich schneller die Befehle abgearbeitet wenn ich einen direkten sql-String abgeschickt habe. Und es ging da nicht um 3 ms. Es ging um einen Faktor 10 oder so. Selbst dann, wenn es sich um Kleinigkeiten gehandelt hat...

    Was genau das Entities dort gemacht hat, weiß ich nicht genau. Aber Du kannst Dir gern mal die Mühe machen und es selbst testen. Ich kann mir nicht vorstellen, dass ein Update auf einen Item schneller per Entity in vergleich zu einem direkten sql String zu Datenbank...

    Übrigens, falls Du Dir doch die Mühe machst und so einen Experiment baust, lade den gerne hoch... Ich würde sehr gern mir den ansehen, damit wir auch was festes zu Diskussion haben.

    EugenIS schrieb:

    Und es ging da nicht um 3 ms. Es ging um einen Faktor 10 oder so.
    Und das hast du auch Warm getestet, also mehr als nur 1 oder 2 mal nacheinander aufgerufen? Je nachdem was das EntityFramework so anstellt (ich tippe auf Reflection zu einem bestimmten Grad), kann ich mir bei einem einmaligen Aufruf von Funktionen etc. einen ziemlichen Overhead vorstellen, der bei weiteren Aufrufen unabhängig vom JIT dank Caching verschwindet.

    EaranMaleasi schrieb:

    Und das hast du auch Warm getestet, also mehr als nur 1 oder 2 mal nacheinander aufgerufen? Je nachdem was das EntityFramework so anstellt (ich tippe auf Reflection zu einem bestimmten Grad), kann ich mir bei einem einmaligen Aufruf von Funktionen etc. einen ziemlichen Overhead vorstellen, der bei weiteren Aufrufen unabhängig vom JIT dank Caching verschwindet.

    Genau das ist der springende Punkt. Gerade EF 6 ist hier beim ersten Aufruf EXTREM langsam. EF 6 besteht aus einer (ich glaube es waren 5 oder 6 MB) großen Bibliothek die erst mal durch den JIT gejagt werden muss.
    Ein kaltstart ist hier also überhaupt nicht zu messen. Warm sieht die Sache anders aus.

    Gerne mach ich einen Test. Ich werde ihn allerdings mit EF Core machen.
    Versuche ich heute abend mal.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##