Sollten Sie ein ORM-Framework aufgeben, wenn Sie eine Massenoperation implementieren müssen?

15

Hier ist eine häufige Situation:

  • Sie müssen eine Massenoperation in einer Anwendung implementieren, die ein ORM-Framework verwendet.
  • Nach dem ersten Durchgang haben Sie erhebliche Leistungsprobleme festgestellt.

Hier ist meine Frage:

  • Sollten Sie in dieser Situation eine Lösung bevorzugen , die unformatiertes SQL enthält?
  • Oder gibt es bekannte Entwurfsmuster, die Ihnen dabei helfen können, Probleme zu verringern, die häufig bei Massenvorgängen mit ORM-Frameworks auftreten?

BEARBEITEN:

  • Ich frage Sie nicht, ob Sie das ORM-Framework aus der gesamten Anwendung entfernen sollen.
  • Ich frage: Sollten Sie auf das ORM-Framework für diesen kleinen Teil der Anwendung verzichten?
Jim G.
quelle
Ich weiß nicht, ob Sie irgendetwas tun sollten , aber haben Sie versucht, Ihre Bulk-Operation zu stapeln ?
ChrisAnnODell

Antworten:

13

ORMs sollen den Zugriff auf Ihre Datenbank nicht vollständig übernehmen. Verwenden Sie sie für die 80% des Codes, der CRUD ist, das Zeug, das zu langweilig ist, um es selbst zu schreiben. Verwenden Sie gespeicherte Prozeduren, dynamisches SQL oder alles, was Sie möchten, für die verbleibenden 20%, die sorgfältig optimiert werden müssen.

Robert Harvey
quelle
4
Das würde funktionieren, wenn die Datenbankabstraktion nicht einer der Hauptgründe für die Verwendung eines ORM wäre.
@ Pierre303, mir fällt es schwer, Ihren Kommentar zu verstehen. Was meinen Sie?
Mark Canlas
@ MarkCanlas: Ich denke, er bedeutet "die Datenbank abstrahieren" in dem Sinne, dass Sie die Datenbank ändern könnten (zB von SQL Server zu MySQL wechseln), wenn Sie dies wollten. In der Praxis tritt dieser Anwendungsfall kaum auf.
Robert Harvey
1
Sie können weiterhin Abstraktionen erstellen. Die meisten ORMs, die tatsächlich mehrere Anbieter / Dialekte unterstützen, unterstützen anbieterspezifischen Code. Sie können Vorgänge als Masseneinfügung / Array-Bindung / TVP / Was auch immer für bestimmte Datenbanken implementieren und für nicht unterstützte Anbieter wie SQLite auf langsam nach langsam zurückgreifen lassen. Im schlimmsten Fall können Sie die möglicherweise umfangreiche Funktionalität in eine separate Schnittstelle / Klasse aufteilen und in eine andere Implementierung untergliedern, die auf Build- oder Konfigurationsparametern basiert.
Aaronaught
Ja, benutzerdefinierte Dialekte können hilfreich sein, ebenso wie spezifischer Code für spezifische Probleme. Damit dies jedoch finanziell tragfähig ist, muss es auf das strikte Minimum beschränkt sein. Unsere Anpassungen durch benutzerdefinierte Funktionen (Dialekte) machen weniger als 0,1% der gesamten Codebasis für den Datenzugriff aus. Ich wäre wirklich besorgt, wenn es mehr wäre.
7

Ich verwende ein ORM (nHibernate) in einer Anwendung, die eine hohe Leistung erfordert und Milliarden von Datensätzen verarbeitet. Mit der Zeit stellten wir fest, dass die wichtigsten Leistungsprobleme eher mit unserer eigenen Art der Verwendung des ORM zusammenhängen als mit dem ORM allein.

Der ORM sollte Ihre obligatorischen Datenbankkenntnisse nicht ersetzen. Es ist ein Tool, mit dem Sie mehr Produktivität und Flexibilität in Ihrem Code erzielen. Sie müssen jedoch die zugrunde liegenden Prozesse kennen, um Ihre Leistung zu optimieren.

Sie haben kein bestimmtes ORM angegeben. Daher haben wir folgende Maßnahmen zur Leistungsverbesserung ergriffen:

  • Wir haben einen ORM-Profiler verwendet. (wir haben nhprof benutzt)
  • Wir haben einen Datenbank-Profiler verwendet. (wir haben SQL Server Profiler verwendet)
  • Wir lesen so viele Artikel wie möglich zu diesem Thema. (Zusätzlich zum gesamten Kapitel zu diesem Thema in der Dokumentation standen viele für nHibernate zur Verfügung.)
  • Wir haben spezielle Bücher über Leistung und Skalierbarkeit gekauft.
  • Wir haben ein Benchmarking-System erstellt, um unsere eigenen Optimierungen zu testen.
  • und was noch wichtiger ist, wir konnten unseren Code mit echten Kunden mit riesigen Daten testen. Allein das hat uns geholfen, die meisten Probleme in unserer Anwendung zu erkennen.
Dan McGrath
quelle
1

Wir haben es mit Entity Framework geschafft, aber unsere Anwendung hat viele Batch-Operationen ausgeführt (wir haben eine große Anzahl von Datensätzen in einzelne Tabellen geschrieben), also war es eine gute Anpassung. Ich würde auf jeden Fall sehen, ob es möglich ist, das ORM-Framework beizubehalten, um die Menge an Spezialcode in Ihrer App zu reduzieren. Ist es möglich, Schreibvorgänge zu puffern und dann als Gruppe auszuführen? Sie verlieren die Transaktionssemantik, aber wenn Sie Massenoperationen durchführen, sind Sie damit vermutlich bereits einverstanden.

TMN
quelle
1

ORMs machen nichts Magisches. Sie übersetzen Objektzugriffsmethoden in SQL. Die SQL-Anweisungen, die sie ausführen, sind nicht unbedingt langsamer als die SQL, die Sie manuell schreiben würden. Dennoch gibt es einige Probleme, auf die Sie stoßen könnten:

  1. Transaktionen: Eine große Massenoperation ist fast immer schneller als viele kleine Transaktionen, die zusammen das gleiche Ziel erreichen. Wenn Ihre ORM-Methodenaufrufe also fein abgestimmte Transaktionen verwenden (die aktiven Methoden im Datensatzstil in Spring Roo-Entitäten werden beispielsweise standardmäßig als @Transactional bezeichnet), sind Massenvorgänge langsam. Wenn dies in Ihrer Anwendung der Fall ist, sollten Sie sich Ihre Transaktionslogik ansehen.
  2. Caching: Im Ruhezustand können Sie mit einem Cache der ersten Ebene Ihrem Entitätsmanager unnötige Roundtrips zur Datenbank ersparen. Das ist im Allgemeinen gut, aber schlecht für Bulk-Inserts, bei denen es zu unnötigem Verstopfen des Caches kommt, was zu einer Verschlechterung der Anwendungsleistung führt. Wenn dies Ihr Problem ist, sollten Sie sich das oben von ChrisAnnODell vorgeschlagene Batching-Muster ansehen. Wir verwenden es in unseren Importeuren und es beschleunigt Masseneinsätze sehr.

Die Verwendung von nativem SQL zur Verbesserung der Leistung ist kein Problem. Aber stellen Sie zuerst sicher, dass Sie verstehen, was Sie bremst.

Wallenborn
quelle
Verwenden Sie eine StatelessSession, um den Cache zu vermeiden. Vermeiden Sie auch automatische Inkrement-IDs. HiLo oder Guid sollten stattdessen verwendet werden.
1

Bypass den ORM. Nicht nur das, sondern auch "reguläre" SQL umgehen. Verwenden Sie ein Massendienstprogramm Ihrer Datenbank, um extrem große Datenmengen in eine Staging-Tabelle einzufügen. Verwenden Sie dann sql, um Ihre Staging-Aktivitäten durchzuführen.

Ihr "Flavor-of-the-Blog" -ORM funktioniert möglicherweise nicht in allen Situationen.

Lord Tydus
quelle
Richtig, diese Art von Back-End-Tools sind mühsam zu erlernen, aber nach 3 oder 4 Durchgängen sind Sie ein Experte und können Dinge schneller erledigen und manchmal Dinge, die auf andere Weise nicht erledigt werden können. Es ist wie der Unterschied zwischen einer Schaufel und einer Planierraupe. Ich habe skriptgesteuerte Tools für verschiedene Plattformen geschrieben, um Texteingabedateien zu lesen und Daten mit Operationen auf niedriger Ebene zu aktualisieren. Das Schreiben eines solchen Tools kann Ihnen das Leben erleichtern (oder zumindest interessanter machen). Solche Dinge können verwendet werden, um Anpassungsdaten auf Clientinstallationen während Softwareupdates zu optimieren.
0

War in dieser Situation. Manchmal muss man.

In einigen ORM-Versionen kann der Entwickler das Objektmodell überspringen und direkt zur Datenbankebene wechseln.

Es gibt auch ORM, die gekapselte Massenoperationen als objektorientiert verwenden.

umlcat
quelle
0

Wie von umlcat erwähnt , gibt es einige ORMs, mit denen Sie Massenoperationen ausführen können.

Darüber hinaus sind viele ORMs erweiterbar, sodass Sie nur Ihre eigene Methode für die Ausführung von Massenvorgängen schreiben können, sofern dies nicht bereits unterstützt wird. Wenn der Massenvorgang in Ihrer Anwendung ein Faktor ist, den Sie ausschließen können, füge ich ihn als Ebene im ORM hinzu (dazu müssen Sie wahrscheinlich unformatiertes SQL schreiben). Verwenden Sie dann in der Anwendung das ORM Methode, die Sie implementiert haben.

Dies erleichtert auch das Testen und Debuggen von Einheiten. Sobald Sie eine gute Testabdeckung für Ihre ORM-Methoden haben, können Sie diese in Ihren Apps verwenden. Andernfalls kann das Debuggen von unformatiertem SQL (insbesondere von großen mit Transaktionen und vielen JOINs) schmerzhaft sein.

Ich habe einmal fast einen Tag gebraucht, um einen Fehler in einem rohen SQL-Aufruf zu entdecken, der fast 100 LOC betrug, und der Fehler war nur ein einzelnes Zeichen! Seitdem versuche ich, Raw-SQL in der App zu vermeiden und alle SQL-Prozeduren separat auf ihre Einheit zu testen.

Attila O.
quelle
0

Nun, es gibt keine Designmuster, die mir bekannt sind. Ich vermute, dass Sie die Entscheidung für das ORM aus einem bestimmten Grund getroffen haben. Daher ist es wahrscheinlich nicht das, was Sie wollen, wenn Sie das ORM aufgeben. In diesen Fällen gibt es meines Erachtens jedoch Raum, beide Lösungen zu mischen. Daran ist nichts auszusetzen, solange Sie dies bewusst tun und dokumentieren, warum Sie von der Standardverwendung des ORM in Ihrer Software abweichen. Darüber hinaus verfügen einige ORM-Frameworks über einige Funktionen für Bulk-Operationen. Ich weiß, dass nHibernate (ORM für das .NET-Framework) StatelessSessions genannt hat, die viel weniger Overhead haben, aber dennoch möglicherweise nicht den Leistungsschub liefern, den Sie suchen. Verwenden Sie in diesem Fall einfach unformatiertes SQL.

Pieter
quelle