Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Czy kolejność klauzul zapytań LINQ powinna wpływać na wydajność Entity Framework?

Sednem pytania nie jest „dlaczego zamówienie ma znaczenie w LINQ?”. LINQ po prostu tłumaczy dosłownie bez zmiany kolejności. Prawdziwe pytanie brzmi „dlaczego te dwa zapytania SQL mają różną wydajność?”.

Udało mi się odtworzyć problem, wstawiając tylko 100 tys. wierszy. W takim przypadku uruchamiana jest słabość optymalizatora:nie rozpoznaje on, że może wykonać wyszukiwanie w Colour ze względu na złożony stan. W pierwszym zapytaniu optymalizator rozpoznaje wzorzec i tworzy wyszukiwanie indeksu.

Nie ma semantycznego powodu, dla którego tak powinno być. Wyszukiwanie po indeksie jest możliwe nawet przy wyszukiwaniu po NULL . To jest słabość/błąd w optymalizatorze. Oto dwa plany:

EF próbuje być tutaj pomocny, ponieważ zakłada, że ​​zarówno kolumna, jak i zmienna filtru mogą mieć wartość null. W takim przypadku próbuje podać dopasowanie (co zgodnie z semantyką C# jest właściwe).

Próbowałem to cofnąć, dodając następujący filtr:

Colour IS NOT NULL AND @p__linq__0 IS NOT NULL
AND Size IS NOT NULL AND @p__linq__1 IS NOT NULL

Mając nadzieję, że optymalizator użyje teraz tej wiedzy do uproszczenia złożonego wyrażenia filtru EF. Nie udało się tego zrobić. Gdyby to zadziałało, ten sam filtr mógłby zostać dodany do zapytania EF, zapewniając łatwą poprawkę.

Oto zalecane przeze mnie poprawki w kolejności, w jakiej należy je wypróbować:

  1. Ustaw kolumny bazy danych nie-null w bazie danych
  2. Spraw, aby kolumny nie miały wartości NULL w modelu danych EF, mając nadzieję, że uniemożliwi to EF utworzenie złożonego warunku filtru
  3. Utwórz indeksy:Colour, Size i/lub Size, Colour . Usuwają również ich problem.
  4. Upewnij się, że filtrowanie odbywa się we właściwej kolejności i zostaw komentarz do kodu
  5. Spróbuj użyć INTERSECT /Queryable.Intersect połączyć filtry. Często skutkuje to różnymi kształtami planów.
  6. Utwórz wbudowaną funkcję z wartościami przechowywanymi w tabeli, która wykonuje filtrowanie. EF może użyć takiej funkcji jako części większego zapytania
  7. Opuść do surowego SQL
  8. Użyj przewodnika po planie, aby zmienić plan

Wszystkie te rozwiązania są obejściami, a nie poprawkami głównych przyczyn.

W końcu nie jestem zadowolony zarówno z SQL Server, jak i EF. Oba produkty powinny zostać naprawione. Niestety, prawdopodobnie nie będą i nie możesz na to czekać.

Oto skrypty indeksujące:

CREATE NONCLUSTERED INDEX IX_Widget_Colour_Size ON dbo.Widget
    (
    Colour, Size
    ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
CREATE NONCLUSTERED INDEX IX_Widget_Size_Colour ON dbo.Widget
    (
   Size, Colour
    ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Oblicz godziny pracy między dwiema datami

  2. Niepoprawna składnia w pobliżu ''

  3. SqlException (0x80131904):nieprawidłowa nazwa obiektu „dbo.Categories”

  4. Jak dodać numer kolejny dla grup w zapytaniu SQL bez tabel tymczasowych

  5. Błąd:nie można użyć widoku lub funkcji z powodu błędów wiązania