15 Stimmen

Warum würde die Verwendung eines DataContext das die Leistung negativ beeinflussen?

Nach einer fairen Menge Forschung und einigen Fehlern habe ich meinen Code so geändert, dass jedes Mal, wenn die Datenbank abgefragt oder Daten eingefügt werden, ein neuer DataContext erstellt wird. Die Datenbank wird häufig abgefragt - für jede der 250.000 Transaktionen, die verarbeitet werden, wird die Datenbank abgefragt, um eine Kunden-ID, eine Abteilungs-ID und eine Kategorie zu erhalten, bevor die Transaktion eingefügt wird.

Jetzt versuche ich, den Code zu optimieren, da er nur etwa 15 Transaktionen pro Sekunde verarbeitet hat. Ich habe einige überflüssige Abfragen entfernt und einige Indizes hinzugefügt und es auf 30/Sekunde gebracht. Dann dachte ich, auch wenn alle sagen, dass ein DataContext leichtgewichtig ist, muss es etwas kosten, jedes Mal einen neuen zu erstellen 4 Mal pro Transaktion, also habe ich versucht, den DataContext wiederzuverwenden. Ich stellte zu meiner Überraschung fest, dass die Wiederverwendung des Kontexts die Leistung auf 10 Transaktionen pro Sekunde verschlechterte!

Warum ist das so? Liegt es daran, dass der DataContext die Entitäten im Speicher zwischenspeichert und zuerst durch seine in-memory-Liste sucht, bevor er die Datenbank abfragt? So dass, wenn ich z.B. nach der Kunden-ID (Primärschlüssel) für den Kunden mit dem Namen 'MCS' suche und die Kundennamen-Spalte einen gruppierten Index darauf hat, sodass die Datenbankabfrage schnell ist, die in-memory-Suche langsamer ist?

Und ist es wahr, dass das Erstellen/Verwerfen so vieler db-Verbindungen die Dinge verlangsamen könnte, oder ist das nur eine weitere voreilige Optimierung? Und wenn es wahr ist, gibt es einen Weg, einen DataContext wiederzuverwenden, aber eine tatsächliche Datenbankabfrage für jede Linq-to-Sql-Abfrage durchzuführen?

0 Stimmen

damit die Datenbankabfrage schnell erfolgt, wird der look-up im Speicher langsamer sein - Niemals, denn der Datenbank-Lookup, wie schnell auch immer, benötigt immer eine Materialisierung auf der Client-Seite. Das Erstellen/Entfernen so vieler Datenbankverbindungen - Das ist nicht das, was passiert, wenn Kontexte erstellt und entfernt werden.

16voto

Aaronontheweb Punkte 7711

Hier ist, warum das Wiederverwenden eines DataContext keine bewährte Methode ist, aus der MSDN DataContext-Dokumentation:

Der DataContext ist die Quelle aller über eine Datenbankverbindung abgebildeten Entitäten. Er verfolgt Änderungen, die Sie an allen abgerufenen Entitäten vorgenommen haben, und pflegt einen "Identitäts-Cache", der sicherstellt, dass mehrfach abgerufene Entitäten durch Verwendung derselben Objektinstanz dargestellt werden.

Im Allgemeinen ist eine DataContext-Instanz so konzipiert, dass sie für eine "Arbeitseinheit" dauert, wie auch immer Ihre Anwendung diesen Begriff definieren mag. Ein DataContext ist leichtgewichtig und nicht teuer in der Erstellung. Eine typische LINQ-to-SQL-Anwendung erstellt DataContext-Instanzen auf Methodenebene oder als Mitglied von kurzlebigen Klassen, die eine logische Gruppe von verwandten Datenbankoperationen darstellen.

Wenn Sie einen DataContext für eine große Anzahl von Abfragen wiederverwenden, wird sich Ihre Leistung aus ein paar möglichen Gründen verschlechtern:

  1. Wenn der in-Memory-Identitätscache des DataContext so groß wird, dass er auf die Auslagerungsdatei schreiben muss, dann wird Ihre Leistung an die Lesezugriffsgeschwindigkeit der Festplatte gebunden sein und effektiv wird es keinen Grund geben, überhaupt einen Cache zu verwenden.

  2. Je mehr Identitätsobjekte im Speicher vorhanden sind, desto länger dauert jeder Speichervorgang.

Im Wesentlichen verletzen Sie damit das UoW-Prinzip für die DataContext-Klasse.

Das Öffnen von Datenbankverbindungen ist mit einem gewissen Overhead verbunden, aber eine Verbindung für eine lange Zeit offen zu lassen (was oft auch bedeutet, eine Tabelle zu sperren) ist weniger bevorzugt als das schnelle Öffnen und Schließen.

Ein weiterer Link, der Ihnen möglicherweise helfen kann, von MSDN:

How to: Wiederverwendung einer Verbindung zwischen einem ADO.NET-Befehl und einem DataContext (LINQ to SQL)

1voto

Ben M Punkte 21694

Auch mit einem gruppierten Index wird die In-Memory-Suche immer schneller sein als eine Datenbankabfrage - außer in Randfällen, wie z.B. einem 386 vs. einem Cray - auch wenn Sie netzwerkbedingte Verzögerungen ausklammern.

Ich würde vermuten, dass die Verschlechterung mit der Handhabung von Entitäten durch den DataContext zusammenhängt: Die Verwendung eines Kontexts erhöht kontinuierlich die Anzahl der überwachten Entitäten, und der Aufruf von SaveChanges könnte mehr Zeit erfordern.

Nochmal, das ist nur eine Vermutung - aber dort würde ich anfangen zu suchen.

1voto

Cade Roux Punkte 85601

Sie müssten alles von Anfang bis Ende profilieren und sehen, wo Ihre Zeit wirklich verbracht wird.

Ein gruppiertes Index ist nicht unbedingt das schnellste, wenn eine Zeile breit ist. Am schnellsten wäre wahrscheinlich ein abdeckender nicht gruppierten Index, aber das ist eigentlich nicht der Punkt.

Ich würde erwarten, dass Sie, um mehr Leistung zu erhalten, wahrscheinlich einen Teil des Frameworks über Bord werfen müssen, wenn Sie die Fähigkeiten nicht wirklich nutzen. Wenn Sie die Fähigkeiten nutzen - nun, dafür bezahlen Sie...

1voto

Phil Sandler Punkte 26854

Nicht genau passend hier, aber haben Sie schon einmal über einen Anwendungscache auf Ebene der Applikation nachgedacht, um die Kunden-ID, Abteilungs-ID und Kategorie abzurufen? Aus Ihrem Beitrag geht nicht hervor, wie viele dieser Entitäten in Ihrem System vorhanden sind oder was beim Abfragen zu deren Erhalt beteiligt ist.

Jedoch, als Beispiel, wenn Sie eine Million Kategorien in Ihrem System haben und deren ID anhand des Kategorienamens abrufen müssen, das Vorhalten eines Namens-/ID-Wörterbuchs im Speicher zur jederzeitigen Abfrage spart Ihnen einen Datenbankzugriff für jede verarbeitete Transaktion. Dies könnte die Leistung massiv verbessern (dies setzt einige Dinge voraus, wie z.B. dass keine neuen Kategorien regelmäßig hinzugefügt werden). Als Faustregel sind Datenbankzugriffe teuer im Vergleich zu In-Memory-Operationen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X