EFCore-Lösung zur Leistungsoptimierung – Abfrage optimieren

Die Datenbankleistung ist ein großes und komplexes Thema, das den gesamten Komponentenstapel betrifft: Datenbank, Netzwerk, Datenbanktreiber und Datenzugriffsschichten (wie EF Core). Obwohl High-Level-Layer und O/RMs wie EF Core die Anwendungsentwicklung erheblich vereinfachen und die Wartbarkeit verbessern, können sie manchmal undurchsichtig sein und leistungskritische interne Details wie das ausgeführte SQL verbergen.

Einige kritisierte Leistungsprobleme waren schon immer ein heißes Thema. Die tatsächliche Situation ist möglicherweise nicht eine schlechte Leistung, sondern wie man Fallen und Gruben vermeidet, die die Leistung beeinträchtigen.

1. Indizes richtig verwenden

Der Hauptfaktor dafür, ob eine Abfrage schnell ausgeführt wird, ist, ob sie Indizes an den richtigen Stellen verwendet: Datenbanken werden häufig zum Speichern großer Datenmengen verwendet, und Abfragen, die ganze Tabellen durchlaufen, sind häufig die Ursache für schwerwiegende Leistungsprobleme.

// 在开始时匹配,使用索引 (SQL Server)
var posts1 = context.Posts.Where(p => p.Title.StartsWith("A")).ToList();
// 在末尾匹配,不使用索引
var posts2 = context.Posts.Where(p => p.Title.EndsWith("A")).ToList();
2. Fragen Sie nur die erforderlichen Attribute ab

EF Core macht es sehr einfach, Entitätsinstanzen zu suchen und sie im Code zu verwenden. Beim Abfragen von Entitätsinstanzen werden jedoch häufig mehr Daten aus der Datenbank abgerufen als benötigt. Betrachten Sie die folgende Situation:

foreach (var blog in context.Blogs)
{
 Console.WriteLine("Blog: " + blog.Url);
}

SQL

SELECT [b].[BlogId], [b].[CreationDate], [b].[Name], [b].[Rating], [b].[Url]...
FROM [Blogs]

Die Möglichkeit, dies zu optimieren, besteht darin, SelectEF mitzuteilen, welche Spalten nachgeschlagen werden sollen, indem Sie Folgendes verwenden:

foreach (var blogName in context.Blogs.Select(b => b.Url))
{
  Console.WriteLine("Blog: " + blogName);
}

SQL

SELECT [b].[Url]
FROM [Blogs] AS [b]

Dieser Ansatz eignet sich hervorragend für schreibgeschützte Abfragen. Wenn Sie jedoch den abgerufenen Blog aktualisieren müssen , wird es kompliziert, da die Änderungsverfolgung von EF nur für Entitätsinstanzen funktioniert.

3. Begrenzen Sie die Größe der Ergebnismenge

Die Anzahl der zurückgegebenen Zeilen hängt von den tatsächlichen Daten in der Datenbank ab. Daher ist es unmöglich zu wissen, wie viele Daten aus der Datenbank geladen werden, wie viel Speicher die Ergebnisse beanspruchen und wann diese Ergebnisse verarbeitet werden (z. B. wenn sie gesendet werden). das Netzwerk an den Browser des Benutzers) fügt zusätzliche Menge der erzeugten Last hinzu.

var blogs25 = context.Posts
 .Where(p => p.Title.StartsWith("A"))
 .Take(5)
 .ToList();
4. Priorisieren Sie die Verwendung asynchroner Async-Methoden

EF Core bietet viele asynchrone Methoden wie xxxAsync. Es wird empfohlen, diese Methoden zu verwenden, um Durchsatz und Leistung zu verbessern und unnötige Verzögerungen und Wartezeiten zu reduzieren.

5. Deaktivieren Sie die Statusverfolgung

Das Nachverfolgungsverhalten bestimmt, ob EF Core Snapshot-Informationen zu Entitätsinstanzen in seinem Änderungs-Tracker speichert. Wenn eine Entität verfolgt wird, werden alle in dieser Entität erkannten Änderungen während SaveChanges() dauerhaft in der Datenbank gespeichert. Abfragen ohne Nachverfolgung sind nützlich, wenn Sie die Daten nur abfragen und nicht ändern möchten. Abfragen ohne Nachverfolgung werden schneller ausgeführt, da keine Snapshot-Nachverfolgungsinformationen für die abfragenden Entitäten festgelegt werden müssen. Nicht-Tracking-Abfragen sollten bevorzugt verwendet werden, wenn keine Notwendigkeit besteht, aus der Datenbank abgerufene Entitäten zu aktualisieren.

//单体查询关闭:
AsNoTracking()
//整个上下文关闭:
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
6. Deaktivieren Sie die DetectChanges- Statussynchronisierung

Beim Abfragen von Daten aus der Datenbank erfasst der Kontext eine Momentaufnahme jedes Entitätsattributs (Datenbankwert, Originalwert, aktueller Wert), und wenn SaveChanges aufgerufen wird, wird intern automatisch die DetectChanges-Methode aufgerufen, die alle Entitäten im Kontext durchsucht Vergleichen Sie den aktuellen Attributwert mit dem ursprünglichen Attributwert, der im Snapshot gespeichert ist. Wenn sich der gefundene Attributwert geändert hat, interagiert EF mit der Datenbank, um die Daten zu aktualisieren.

Bewirkt, dass die DetectChanges-Methoden automatisch aufgerufen werden: Find, Local, Remove, Add, Update, Attach, SaveChanges und

Eintritt usw.

Der automatische Synchronisierungsstatus wird jedoch häufig aufgerufen, und die automatische Synchronisierung der oben genannten Methoden kann manuell deaktiviert werden. Wenn die Daten geändert werden, wird eine einmalige manuelle Synchronisierung durchgeführt.

context.ChangeTracker.AutoDetectChangesEnabled = false;
//执行操作后手动同步状态
context.ChangeTracker.DetectChanges();
7. Verwenden Sie EF.Functions.xxx für Fuzzy-Abfragen

EF Core unterstützt die Verwendung der Methoden „StartsWith“, „Contains“ und „EndsWith“ für Fuzzy-Abfragen. Diese Methoden werden in LIKE-Anweisungen übersetzt, aber um die Leistung zu verbessern, wird auch eine EF.Functions.Like-Methode bereitgestellt. Die von dieser Methode generierte SQL-Anweisung hat bessere Leistung.

var result= context.Blogs.Where(b => EF.Functions.Like(b.BlogName, "%xcode%"))
8. Effiziente Paginierung

Unter Paginierung versteht man das Abrufen von Ergebnissen in Seiten und nicht in allen auf einmal. Dies erfolgt typischerweise bei großen Ergebnismengen, bei denen eine Benutzeroberfläche angezeigt wird, die es dem Benutzer ermöglicht, zur nächsten oder vorherigen Ergebnisseite zu navigieren.

9. Pufferung und Streaming

Pufferung bedeutet, dass alle Abfrageergebnisse in den Speicher geladen werden, während Streaming bedeutet, dass EF die Ergebnisse einzeln an die Anwendung liefert und niemals die gesamte Ergebnismenge im Speicher behält. Im Prinzip sind die Speicheranforderungen für Streaming-Abfragen festgelegt: Die Speicheranforderungen sind gleich, unabhängig davon, ob die Abfrage 1 Zeile oder 1000 Zeilen zurückgibt. Andererseits gilt: Je mehr Zeilen zurückgegeben werden, desto mehr Speicher wird zum Puffern der Abfrage benötigt. Bei Abfragen, die große Ergebnismengen erzeugen, kann dies ein wichtiger Leistungsfaktor sein.

// oList和ToArray会导致整个结果集被缓冲:
var blogsList = context.Posts.Where(p => p.Title.StartsWith("A")).ToList();
var blogsArray = context.Posts.Where(p => p.Title.StartsWith("A")).ToArray();
// foreach流式,每次处理一行:
foreach (var blog in context.Posts.Where(p => p.Title.StartsWith("A")))
{
 // ...
}

Wenn Ihre Abfrage nur wenige Ergebnisse liefert, brauchen Sie sich darüber wahrscheinlich keine Sorgen zu machen. Wenn jedoch die Anzahl der Zeilen, die von einer Abfrage zurückgegeben werden können, sehr hoch ist, kann es sich lohnen, Streaming statt Pufferung in Betracht zu ziehen.

10. Laden Sie verwandte Entitäten vor

Es gibt ein klassisches Problem in ORM, nämlich das N+1-Problem, das im Allgemeinen bei Eins-zu-Viele-Abfragen auftritt. Das N+1-Problem entsteht auf diese Weise: Fragen Sie die Haupttabelle einmal ab, erhalten Sie N Datensätze und fragen Sie die zugehörige Untertabelle basierend auf den N Datensätzen ab, was N-mal erforderlich ist. Bei großen Datenmengen wird die Leistung des Datenpfads stark beansprucht.

Beim eifrigen Laden in EFCore werden zugehörige Daten aus der Datenbank als Teil der ersten Abfrage geladen, sodass alle erforderlichen Daten in einem Roundtrip abgerufen werden können.

Verwenden Sie Includedie Methode, um die zugehörigen Daten anzugeben, die in die Abfrageergebnisse einbezogen werden sollen:

var blogs = context.Blogs
 .Include(blog => blog.Posts)
 .ToList();

Jede Technologie hat zwei Seiten. Der Vorteil der Verwendung des N+1-Modus besteht darin, dass ein Teil der Daten separat zwischengespeichert werden kann.

11. Verwenden Sie rohes SQL

In einigen Fällen ist für Ihre Abfrage optimierteres SQL vorhanden, und EF kann ein solches SQL nicht generieren. In diesen Fällen kann das manuelle Schreiben des SQL die Leistung erheblich verbessern, beispielsweise über FromSqlRaw .

おすすめ

転載: blog.csdn.net/gcf10080353/article/details/131716268