2016-11-20 5 views
0

Ich habe diese Abfrage, die in einer Produktionsumgebung sehr langsam ist. Ich würde gerne wissen, warum und ob es einen besseren Weg gibt, das gleiche Ergebnis zu erzielen.Warum ist meine Linq zu SQL-Abfrage sehr langsam?

public async Task<Membership> FindByEmailByAccessL1OrL3OrL4Async(string email) 
{ 
    return await (from m in this.Queryable() 
        where m.Email == email 
         && (m.RoleMemberships.Select(r => r.RoleId).Contains(RoleConstants.ACCESSGRANTEDL1ID) 
          || m.RoleMemberships.Select(r => r.RoleId).Contains(RoleConstants.ACCESSGRANTEDL3ID) 
          || m.RoleMemberships.Select(r => r.RoleId).Contains(RoleConstants.ACCESSGRANTEDL4ID)) 
        select m).SingleOrDefaultAsync(); 
} 

Kurz gesagt, der Zweck dieser Abfrage besteht darin, eine Benutzermitgliedschaft per E-Mail zu erhalten und mit einem Login fortzufahren. Mehr habe ich Benutzermitgliedschaften, mehr diese Abfrage wird langsam sein.

Danke,

David

bearbeiten

this.Queryable() das Äquivalent ist select * from Memberships zu tun. Membership Tabelle hat viele Rollen, und eine Rolle hat viele Mitgliedschaften.

Auch Mitgliedschaft Tabelle dauert bis zu 12 Sekunden, um die Login-Informationen für 240 Zeilen zu erhalten. Ich muss nach der Rolle filtern, weil der E-Mail-Wert im System nicht eindeutig ist. Nur einige Rollen haben Zugriff auf die Anmeldung und diese Rollen haben eindeutige E-Mails. Deshalb muss ich filtern. Diese Abfrage gibt eine Mitgliedschaft zurück, um mit der Anmeldung fortzufahren, die mit der obigen Abfrage ausgewählt wurde. Also keine IQueryable, IEnumerable oder List, nur der SingleOrDefault Wert.

+0

'this.Queryable()' ??? Du gibst nicht viele Informationen .. Was ist 'das'? Was gibt die 'Queryable()' Methode zurück? Zeigen Sie diesen Code? – user3185569

+0

Sorry! Der Code befindet sich in einer Repository-Architektur. Ich habe mehr Informationen im Abschnitt Bearbeiten gegeben. –

+0

Wir müssten wahrscheinlich die SQL-Tabellendefinitionen zusammen mit irgendwelchen Indizes sehen. – RBarryYoung

Antwort

3

Ich denke, die erzeugte Abfrage ist sehr schlecht, da Sie die gleiche Sache mehrmals tun, das ist:

m.RoleMemberships.Select(r => r.RoleId) 

Stattdessen können Sie einmal das tun mit:

public Task<Membership> FindByEmailByAccessL1OrL3OrL4Async(string email) 
{ 
    return (from m in this.Queryable() 
      where m.Email == email 
       && (m.RoleMemberships.Any(
        r => r.RoleId == RoleConstants.ACCESSGRANTEDL1ID 
         || r.RoleID == RoleConstants.ACCESSGRANTEDL3ID 
         || r.RoleID == RoleConstants.ACCESSGRANTEDL4ID) 
      select m).SingleOrDefaultAsync(); 
} 

Die oben würde die Dinge besser machen, denke ich. Sie können die generierte Abfrage in beiden Fällen mit dem Debugger überprüfen.

Beachten Sie auch, dass Sie nicht auf das Ergebnis warten müssen, einfach die Aufgabe zurückgeben und der Anrufer müsste darauf warten.

+0

"ist sehr Band" - meinst du "schlecht", "breit" oder etwas anderes? –

+0

@MarkSchultheiss Tippfehler behoben. Danke, dass du darauf hingewiesen hast. – user3185569

0

Ich denke, dass es viel von Daten zu laden und EF ist sehr langsam Mapping-Technologie, die interessante Abfragen erstellt (Sie können dies sehen here) Haben Sie Probleme mit der Leistung? Vielleicht sollten Sie andere Mapping-Technologie (Stacks dapper zum Beispiel Dapper). Als wir Tests machten, war es zweimal schneller als EF.

+0

Wie folgst du daraus, dass EF hier im Spiel ist? –

+0

Noch einmal, wenn wir große Daten haben, ist es nicht schnell, deshalb denke ich, dass es diese Situation ist –