Ich habe das Mantra "Nicht vorzeitig optimieren" befolgt und meinen WCF-Service mit Entity Framework codiert.
Ich habe jedoch die Leistung profiliert und das Entity Framework ist zu langsam. (Meine App verarbeitet 2 Nachrichten in ca. 1,2 Sekunden, wobei die (Legacy-) App, die ich neu schreibe, 5-6 Nachrichten gleichzeitig ausführt. (Die Legacy-App ruft Sprocs für ihren DB-Zugriff auf.)
Meine Profilerstellung zeigt, dass Entity Framework den größten Teil der Zeit pro Nachricht benötigt.
Also, was sind meine Optionen?
Gibt es da draußen bessere ORMs?
(Etwas, das nur das normale Lesen und Schreiben von Objekten unterstützt und es schnell macht ..)Gibt es eine Möglichkeit, Entity Framework schneller zu machen?
( Hinweis : Wenn ich schneller sage, meine ich auf lange Sicht nicht den ersten Anruf. (Der erste Anruf ist langsam (15 Sekunden für eine Nachricht), aber das ist kein Problem. Ich brauche ihn nur, um für den Rest schnell zu sein der Nachrichten.)Eine mysteriöse dritte Option, die mir hilft, mehr Geschwindigkeit aus meinem Dienst herauszuholen.
HINWEIS: Die meisten meiner DB-Interaktionen sind Erstellen und Aktualisieren. Ich wähle sehr wenig aus und lösche.
quelle
Antworten:
Beginnen Sie mit der Profilerstellung der SQL-Befehle, die tatsächlich vom Entity Framework ausgegeben werden. Abhängig von Ihrer Konfiguration (POCO, Self-Tracking-Entitäten) gibt es viel Raum für Optimierungen. Mit der
ObjectSet<T>.ToTraceString()
Methode können Sie die SQL-Befehle debuggen (die sich nicht zwischen Debug- und Release-Modus unterscheiden sollten) . Wenn Sie auf eine Abfrage stoßen, die einer weiteren Optimierung bedarf, können Sie einige Projektionen verwenden, um EF weitere Informationen darüber zu geben, was Sie erreichen möchten.Beispiel:
Könnte ersetzt werden durch:
Ich habe das nur aus meinem Kopf getippt, so dass es nicht genau so ausgeführt wird, aber EF führt tatsächlich einige nette Optimierungen durch, wenn Sie ihm alles erzählen, was Sie über die Abfrage wissen (in diesem Fall benötigen wir die Kategorie-). Namen). Dies ist jedoch nicht mit einem eifrigen Laden (db.Products.Include ("Categories")) vergleichbar, da Projektionen die zu ladende Datenmenge weiter reduzieren können.
quelle
Tatsache ist, dass Produkte wie Entity Framework IMMER langsam und ineffizient sind, da sie viel mehr Code ausführen.
Ich finde es auch albern, dass Leute vorschlagen, LINQ-Abfragen zu optimieren, die generierte SQL zu betrachten, Debugger zu verwenden, vorkompilieren, viele zusätzliche Schritte unternehmen usw., dh viel Zeit verschwenden. Niemand sagt - Vereinfachen! Jeder möchte die Dinge weiter verkomplizieren, indem er noch mehr Schritte unternimmt (Zeitverschwendung).
Ein vernünftiger Ansatz wäre, EF oder LINQ überhaupt nicht zu verwenden. Verwenden Sie einfaches SQL. Daran ist nichts auszusetzen. Nur weil die Programmierer eine Herdenmentalität haben und sie den Drang verspüren, jedes einzelne neue Produkt zu verwenden, heißt das nicht, dass es gut ist oder funktionieren wird. Die meisten Programmierer denken, wenn sie jeden neuen Code einbauen, der von einem großen Unternehmen veröffentlicht wird, werden sie zu einem intelligenteren Programmierer. überhaupt nicht wahr. Bei der intelligenten Programmierung geht es hauptsächlich darum, mit weniger Kopfschmerzen, Unsicherheiten und in kürzester Zeit mehr zu erreichen. Behalte die Zeit im Kopf! Das ist das wichtigste Element. Versuchen Sie also, Wege zu finden, um es nicht mit der Lösung von Problemen in schlechtem / aufgeblähtem Code zu verschwenden, der einfach geschrieben wurde, um einigen seltsamen sogenannten "Mustern" zu entsprechen.
Entspannen Sie sich, genießen Sie das Leben, machen Sie eine Pause vom Codieren und verwenden Sie keine zusätzlichen Funktionen, Codes, Produkte oder Muster mehr. Das Leben ist kurz und das Leben Ihres Codes ist noch kürzer, und es ist sicherlich keine Raketenwissenschaft. Entfernen Sie Ebenen wie LINQ, EF und andere, und Ihr Code wird effizient ausgeführt, skaliert und ist dennoch leicht zu warten. Zu viel Abstraktion ist ein schlechtes "Muster".
Und das ist die Lösung für Ihr Problem.
quelle
Ein Vorschlag besteht darin, LINQ to Entity Framework nur für CRUD-Anweisungen mit einem Datensatz zu verwenden.
Schreiben Sie für umfangreichere Abfragen, Suchen, Berichte usw. eine gespeicherte Prozedur und fügen Sie sie dem Entity Framework-Modell hinzu, wie in MSDN beschrieben .
Dies ist der Ansatz, den ich bei einigen meiner Websites gewählt habe, und es scheint ein guter Kompromiss zwischen Produktivität und Leistung zu sein. Entity Framework generiert nicht immer das effizienteste SQL für die jeweilige Aufgabe. Und anstatt die Zeit damit zu verbringen, herauszufinden, warum, spart mir das Schreiben einer gespeicherten Prozedur für die komplexeren Abfragen tatsächlich Zeit. Sobald Sie mit dem Prozess vertraut sind, ist es nicht allzu mühsam, Ihrem EF-Modell gespeicherte Prozesse hinzuzufügen. Und natürlich ist der Vorteil des Hinzufügens zu Ihrem Modell, dass Sie all die stark typisierte Güte erhalten, die durch die Verwendung eines ORM entsteht.
quelle
Wenn Sie nur Daten abrufen, ist dies eine große Hilfe für die Leistung, wenn Sie EF anweisen, die von ihm abgerufenen Entitäten nicht im Auge zu behalten. Verwenden Sie dazu MergeOption.NoTracking. EF generiert lediglich die Abfrage, führt sie aus und deserialisiert die Ergebnisse für Objekte, versucht jedoch nicht, Entitätsänderungen oder ähnliches zu verfolgen. Wenn eine Abfrage einfach ist (nicht viel Zeit darauf wartet, dass die Datenbank zurückgegeben wird), kann die Einstellung auf NoTracking die Abfrageleistung verdoppeln.
Siehe diesen MSDN-Artikel in der MergeOption-Enumeration:
Identitätsauflösung, Statusverwaltung und Änderungsverfolgung
Dies scheint ein guter Artikel über die EF-Leistung zu sein:
Leistung und das Entity Framework
quelle
Sie sagen, dass Sie die Anwendung profiliert haben. Haben Sie auch das ORM profiliert? Es gibt einen EF-Profiler von Ayende, der hervorhebt, wo Sie Ihren EF-Code optimieren können. Sie finden es hier:
http://efprof.com/
Denken Sie daran, dass Sie neben Ihrem ORM einen herkömmlichen SQL-Ansatz verwenden können, wenn Sie die Leistung steigern möchten.
Gibt es ein schnelleres / besseres ORM? Abhängig von Ihrem Objekt / Datenmodell können Sie eines der Mikro-ORMs wie Dapper , Massive oder PetaPoco verwenden .
Auf der Dapper-Website werden einige vergleichende Benchmarks veröffentlicht, die Ihnen eine Vorstellung davon geben, wie sie mit anderen ORMs verglichen werden. Es ist jedoch erwähnenswert, dass die Mikro-ORMs den umfangreichen Funktionsumfang der vollständigen ORMs wie EF und NH nicht unterstützen.
Vielleicht möchten Sie einen Blick auf RavenDB werfen . Dies ist eine nicht relationale Datenbank (wieder von Ayende), mit der Sie POCOs direkt speichern können, ohne dass eine Zuordnung erforderlich ist . RavenDB ist für Lesevorgänge optimiert und erleichtert den Entwicklern das Leben erheblich, da keine Manipulationen mehr erforderlich sind und Ihre Objekte diesem Schema zugeordnet werden müssen. Beachten Sie jedoch, dass dies ein erheblich anderer Ansatz zur Verwendung eines ORM-Ansatzes ist und diese auf der Produktwebsite beschrieben werden .
quelle
Ich habe die Antwort von @Slauma hier sehr nützlich gefunden, um die Dinge zu beschleunigen. Ich habe sowohl für Einfügungen als auch für Aktualisierungen das gleiche Muster verwendet - und die Leistung ist rasant gestiegen.
quelle
Meiner Erfahrung nach liegt das Problem nicht bei EF, sondern beim ORM-Ansatz selbst.
Im Allgemeinen leiden alle ORMs unter N + 1- Problemen, nicht optimierten Abfragen usw. Meine beste Vermutung wäre, Abfragen aufzuspüren, die zu Leistungseinbußen führen, und zu versuchen, das ORM-Tool zu optimieren oder diese Teile mit SPROC neu zu schreiben.
quelle
Dies ist eine einfache Nicht-Framework- und Nicht-ORM-Option, die mit 10.000 / Sekunde mit etwa 30 Feldern geladen wird. Läuft auf einem alten Laptop, also wahrscheinlich schneller als in einer realen Umgebung.
https://sourceforge.net/projects/dopersistence/?source=directory
quelle
Ich bin auch auf dieses Problem gestoßen. Ich hasse es, auf EF zu werfen, weil es so gut funktioniert, aber es ist nur langsam. In den meisten Fällen möchte ich nur einen Datensatz finden oder aktualisieren / einfügen. Selbst einfache Operationen wie diese sind langsam. Ich habe 1100 Datensätze von einer Tabelle in eine Liste zurückgezogen, und dieser Vorgang dauerte mit EF 6 Sekunden. Für mich ist das zu lang, selbst das Speichern dauert zu lange.
Am Ende habe ich mein eigenes ORM gemacht. Ich habe die gleichen 1100 Datensätze aus einer Datenbank abgerufen und mein ORM dauerte 2 Sekunden, viel schneller als EF. Alles mit meinem ORM ist fast augenblicklich. Die einzige Einschränkung im Moment ist, dass es nur mit MS SQL Server funktioniert, aber es könnte geändert werden, um mit anderen wie Oracle zu arbeiten. Ich benutze momentan MS SQL Server für alles.
Wenn Sie mein ORM ausprobieren möchten, finden Sie hier den Link und die Website:
https://github.com/jdemeuse1204/OR-M-Data-Entities
Oder wenn Sie Nugget verwenden möchten:
PM> Install-Package OR-M_DataEntities
Dort ist auch die Dokumentation
quelle
Eine Optimierung ist erst nach dem Profilieren sinnvoll. Wenn Sie feststellen, dass der DB-Zugriff langsam ist, können Sie auf gespeicherte Prozeduren umstellen und EF beibehalten. Wenn Sie feststellen, dass der EF selbst langsam ist, müssen Sie möglicherweise zu einem anderen ORM wechseln oder überhaupt keinen ORM verwenden.
quelle
Wir haben eine ähnliche Anwendung (Wcf -> EF -> Datenbank), die problemlos 120 Anfragen pro Sekunde ausführt. Daher bin ich mir mehr als sicher, dass EF hier nicht Ihr Problem ist. Allerdings habe ich bei kompilierten Abfragen erhebliche Leistungsverbesserungen festgestellt.
quelle
Ich habe EF, LINQ to SQL und dapper verwendet. Dapper ist der schnellste. Beispiel: Ich brauchte 1000 Hauptdatensätze mit jeweils 4 Unterdatensätzen. Ich habe LINQ für SQL verwendet, es dauerte ungefähr 6 Sekunden. Ich wechselte dann zu dapper, holte 2 Datensatzgruppen aus der einzelnen gespeicherten Prozedur und fügte für jeden Datensatz die Unterdatensätze hinzu. Gesamtzeit 1 Sekunde.
Auch die gespeicherte Prozedur verwendet Tabellenwertfunktionen mit Kreuz anwenden, ich fand Skalarwertfunktionen sehr langsam.
Mein Rat wäre, EF oder LINQ to SQL zu verwenden und in bestimmten Situationen auf dapper umzuschalten.
quelle
Das Entity Framework sollte selbst keine größeren Engpässe verursachen. Es besteht die Möglichkeit, dass es andere Ursachen gibt. Sie könnten versuchen, EF auf Linq2SQL umzustellen, beide haben Vergleichsfunktionen und der Code sollte leicht zu konvertieren sein, aber in vielen Fällen ist Linq2SQL schneller als EF.
quelle