2016-11-10 4 views
4

Wir haben eine EF4-Abfrage, die etwa 10 Sekunden dauert. Die Abfrage ist nicht so komplex, aber da viele verwandte Tabellen enthalten sind, dauert es sehr lange. Ich versuche es zu beschleunigen.Warum dauert diese EF-Abfrage so lange?

Die ursprüngliche Abfrage in etwa so aussieht (aus Gründen der Übersichtlichkeit gekürzt) ...

var supportTickets = ctx.SupportTickets 
    .Include(s => s.System.Customer.Country) 
    .Include(s => s.System.Site.Address.Country) 
    // other includes omitted 
    .OrderByDescending(s => s.ID) 
    .ToList(); 
var ticketsList = supportTickets 
    .Select(CreateSupportTicketListOverview) 
    .ToList(); 

CreateSupportTicketListOverview() ist eine Methode, die das Unternehmen und gibt einen DTO darauf basierenden nimmt. Eine verkürzte Version davon sieht wie folgt aus ...

private static SupportTicketListOverview CreateSupportTicketListOverview(SupportTicket x) 
    { 
    return new SupportTicketListOverview { 
     ID = x.ID, 
     SystemNumber = x.System != null ? x.System.SystemNumber : "", 
     CustomerName = x.System != null && x.System.Customer != null ? x.System.Customer.Name : "", 
     ShortSummary = x.ShortSummary, 
     SiteName = x.Site != null ? x.Site.SiteName : "", 
     Status = x.Status != null ? x.Status.Description : "", 
     // other properties omitted for clarity 
    }; 
    } 

Wie gesagt, dies dauert ca. 10 Sekunden und gibt knapp 4000 Ergebnisse. SQL Server Profiler zeigt, dass die Abfrage etwa 6,6 Sekunden dauerte. Wenn wir die generierte SQL-Datei kopieren und diese selbst ausführen, dauert es nur ca. 2 Sekunden, was mich verwirrt. Warum ist es so viel schneller, wenn es alleine läuft? Die Zeit, die zum Erstellen der Entitäten benötigt wird, wäre nicht in der Datenbankabfrage enthalten, oder? Wenn es so wäre, wie viel Zeit würde ich damit verbringen?

Ich habe versucht, dies zu verbessern, indem Sie Tracking deaktivieren und nur die erforderlichen Daten aus der Datenbank ziehen, anstatt die vollständigen Entitäten. Der überarbeitete Code sieht so aus (erneut zur besseren Übersichtlichkeit gekürzt) ...

var tickets = ((SalesTrackerCRMEntities) getContext()).SupportTickets 
     .AsNoTracking() 
     .Include(s => s.System.Customer.Country) 
     .Include(s => s.System.Site.Address.Country) 
     .OrderByDescending(s => s.ID) 
     .Select(t => new { 
     SystemNumber = t.System != null ? t.System.DHRNumber : "", t.ID, 
     CustomerName = t.System != null && t.System.Customer != null ? t.System.Customer.Name : "", 
     SiteName = t.Site != null ? t.Site.SiteName : "", 
     Status = t.Status != null ? t.Status.Description : "", 
     // other stuff omitted 
     }) 
     .AsEnumerable(); 
    var tickets1 =tickets 
     .Select(t => new SupportTicketListOverview { 
     ID = t.ID, 
     SystemNumber = t.SystemNumber, 
     CustomerName = t.CustomerName, 
     ShortSummary = t.ShortSummary, 
     SiteName = t.SiteName, 
     Status = t.Status, 
     // other stuff omitted 
     }) 
     .ToList(); 

Zu meiner Überraschung dauerte dies etwa 15 Sekunden. Beim Suchen im Profiler dauerte die Datenbankabfrage selbst ungefähr 0,7 s, dh zehnmal schneller als die ursprüngliche Abfrage, aber die EF-Abfrage dauerte insgesamt 50% länger als.

Also ich bin völlig verwirrt. Ich habe ein wenig gesucht, aber alle Ratschläge, die ich fand, waren für Dinge, die ich bereits mache. Zum Beispiel gibt this blog post sieben Möglichkeiten zur Verbesserung der EF-Leistung. Dazu gehört, dass man das Repository-Muster nicht verwendet (war nicht wirklich sicher, was er hier meinte, da er kein Beispiel gezeigt hatte, wie man es macht oder nicht), nicht mit Paging (wir nicht), mit Projektionen (Wir sind, zumindest in der neuen Abfrage, beim Ausschalten des Lazy-Ladens (es war schon ausgeschaltet), bei der Deaktivierung des Trackings (bereits geschehen) und bei der Verwendung von Indizes für die Tabellen (wir sind bereits vorhanden). Der letzte Tipp war, die Anzahl der Abfragen zu reduzieren. Ich kann nicht sehen, wie wir das hier machen können, da wir alle relevanten Daten benötigen.

Zusammenfassend dauert die ursprüngliche Datenbankabfrage 6,6s, und die gesamte EF-Abfrage dauert 10s. Die überarbeitete Abfrage dauert .7s für den Datenbank-Teil, aber 15s für die gesamte EF-Abfrage. All diese sind viel zu lang.

Kann jemand beraten, wie ich die Abfrage beschleunigen kann? Danke

+0

Ist Ihr Datenbankserver in einer anderen Region? Ich hatte ein ähnliches Problem, als meine Azure-Web-App in der US-Region und meine Datenbank (fälschlicherweise) in Brasilien gehostet wurde. – Developer

+1

Sind die Tabellen, auf die Sie zugreifen, richtig indiziert? EF4 saugt in Bezug auf die Zusammenstellung einer anständigen Abfrage. –

+2

http://stackoverflow.com/questions/2876616/returning-ienumerablet-vs-iqueryablet – Hackerman

Antwort

0

Welche Version von SQL Server verwenden Sie? Wenn es 2016 ist, können Sie den Abfragespeicher (https://msdn.microsoft.com/en-us/library/dn817826.aspx) aktivieren und herausfinden, welche t-sql-Abfrage von Ihrer EF4-Abfrage ausgeführt wird. Wenn es eine ältere Version ist, können Sie während der Ausführung der EF4-Abfrage diesen (http://blog.sqlauthority.com/2009/01/07/sql-server-find-currently-running-query-t-sql/) verwenden, um nach Abfragetext zu suchen und zu sehen, warum die Abfrage langsam ist, indem Sie sie auf dem Server ausführen und den Plan/fehlende Indizes/etc analysieren.

+0

Danke, aber wie ich in meiner ursprünglichen Frage sagte, wenn wir die SQL in SSMS kopieren, dauert es nur etwa 2s, so dass das nicht das Problem ist. –

Verwandte Themen