2016-11-08 1 views
1

Ich wurde gebeten, die Ursache einer schlecht funktionierenden Abfrage in unserer Datenbank zu untersuchen. Ich habe festgestellt, dass es von einer LINQ-Anweisung generiert wurde und es zum Quellcode zurückverfolgt und in linqpad geladen wurde. In Linqpad habe ich das generierte SQL angezeigt (siehe unten). Wie Sie sehen, ist der erste Teil der WHERE-Klausel unnötig und verlangsamt die Abfrage erheblich, indem er Indizes vermeidet. Es sollte nur auf den DocumentStorageId Schlüssel abfragen und das war's. Es gibt keinen Sinn für die Anweisung IN(), jede Zeile in der Produkttabelle hat einen dieser Werte und ist nicht null. Irgendwelche Ideen, wie ich meine linq-Anweisung ändern kann, so dass die ID zuerst und von Indizes getroffen wird?Warum generiert diese Entitätsframework-LINQ-Abfrage eine langsame Where-Klausel?

void Main() 
{ 
    var uow = new UnitOfWork(this); 
    var repo = new Repository<Product>(this,uow); 
    var documentStorageId = new Guid("473BAE6B-A1A1-49BE-9FD5-AB6B870A82B1"); 
    var result = repo.Queryable() 
       .Where(x => x.DocumentStorageId == documentStorageId)     
       .FirstOrDefault(); 
    result.Dump();    
} 

generiert SQL Ausgang:

SELECT  
     [Extent1].[AColumn], 
     [Extent1].[BColumn] 
    FROM [dbo].[Product] AS [Extent1] 
    WHERE 
      ([Extent1].[ProductType] IN  
       (N'Type1',N'Type2',N'Type3',N'Type4',N'Type5',N'Type6')) 
    AND ([Extent1].[DocumentStorageId] = @p__linq__0) 

EDIT: weiter zu klären, das Modell erstellt wird mit Code zuerst. Produkt ist eine Basisklasse. Es gibt 6 abgeleitete Produkttypen (Typ1, Typ2 usw.). ProductType ist die Diskriminatorspalte. Es sieht so aus, als würde EF versuchen, jede mögliche Produktart einzubeziehen, aber warum? Das Einschließen von all ist gleichbedeutend damit, kein bestimmtes zu spezifizieren, und die IN() -Klausel lässt die Abfrage langsam ablaufen.

+1

Ich bin mir nicht sicher, warum das 'IN' hier nur mit einem einfachen' .Where (x => x.Id == Id) verwendet wird. Sind Sie sicher, dass es irgendwo keine zusätzlichen Einschränkungen gibt? –

+0

Ja, ich stimme travis zu, dies wird nicht durch den Code verursacht, den Sie gepostet haben, können Sie bitte Ihren Modell- und Modellkonfigurationscode posten. –

+0

@Travis Wie ich in der Frage sagte, wenn ich die Top-Anweisung in LinqPad und klicken Sie auf "Show Generated SQL" klicken, bekomme ich den Boden. Ich weiß, es macht keinen Sinn und ist nicht optimal, deshalb poste ich diese Frage. – redwards510

Antwort

0

Mit TPH typisierte Abfragen wie die, die Sie tun EF muss herausfinden, welche Arten Sie interessiert sind. Es weiß nicht, es hat eine vollständige Liste von Typen, nur wenn Sie den Stammtyp in Ihrer Anwendung anfordern Liste der abgeleiteten Typen ist wie folgt. Das bedeutet, dass EF die Liste der Typen enthalten muss, um Probleme zu vermeiden.

Es gibt zwei Möglichkeiten, dies zu beheben.

  1. Bind ein nicht-tph DbSet in Ihrem Kontext und verwenden.
  2. einen Index auf (Product, DocumentStorageId) hinzufügen, so dass die hier in
+0

Dies ist eine Tabelle pro Hierarchie. ProductType ist die Diskriminatorspalte. – redwards510

+0

@ redwards510 aktualisierte Antwort. Das Konzept und die Lösungen sind die gleichen :) –

+0

Ich wählte dies als die Antwort, weil es einige umsetzbare Antworten hatte, obwohl ich # 1 nicht wirklich verstehe. Das Wiederherstellen unserer gesamten Datenbank ist keine Option. Ich habe Query Analyzer verwendet, um einige Indizes vorzuschlagen und diese zur Verbesserung der Leistung zu verwenden. – redwards510

0

Es gibt 6 abgeleitete Produkttypen (Typ1, Typ2, etc.) schnell sein kann. ProductType ist die Diskriminatorspalte.

Sie wissen das ... aber EF kennt das nicht. Nach allem, was Sie wissen, haben Sie 20 Produkttypen drin, aber nur EF über diese 6. Stellen Sie sich die Verwirrung vor, wenn Sie nach allen von ihnen gefragt haben, und es brachte 20 zurück, obwohl es nur 6 für Sie programmiert sind.

Warum generiert diese Entity Framework-LINQ-Abfrage eine langsame Where-Klausel?

Damit eine Abfrage wie erwartet zurückgegeben wird, wird daher die Klausel in verwendet. (Auch einer der Gründe, warum ich TPT gegenüber TPH bevorzuge).

+0

TPT ist noch weniger Abfrage-freundlich. –

+0

IMHO Ein Join ist freundlicher als eine Diskriminator Spalte zusätzlich zu der Tatsache, dass es tatsächlich eine normalisierte Tabelle ist. –

+0

Sicher, das Datenmodell ist viel besser, aber ein äußerer Join pro Untertyp beim Abfragen aller Typen, hmm ... (Erzähle es niemandem, aber ich versuche immer, Vererbung mit EF zu vermeiden.) –

Verwandte Themen