Widzę naprawdę dziwne perf związane z bardzo prostym zapytaniem używającym Entity Framework Code-First z .NET Framework w wersji 4. Zapytanie LINQ2Entities wygląda następująco:
context.MyTables.Where(m => m.SomeStringProp == stringVar);
Wykonanie tego zajmuje ponad 3000 milisekund. Wygenerowany SQL wygląda bardzo prosto:
SELECT [Extent1].[ID], [Extent1].[SomeStringProp], [Extent1].[SomeOtherProp],
...
FROM [MyTable] as [Extent1]
WHERE [Extent1].[SomeStringProp] = '1234567890'
To zapytanie jest uruchamiane niemal natychmiast po uruchomieniu za pośrednictwem Management Studio. Kiedy zmieniam kod C #, aby użyć funkcji SqlQuery, działa w 5-10 milisekund:
context.MyTables.SqlQuery("SELECT [Extent1].[ID] ... WHERE [Extent1].[SomeStringProp] = @param", stringVar);
Tak więc, dokładnie ten sam kod SQL, wynikowe encje są śledzone w obu przypadkach, ale różnica między nimi jest szalona. Co daje?
performance
entity-framework
ef-code-first
Brian Sullivan
źródło
źródło
Performance Considerations for Entity Framework 5
Odpowiedzi:
Znalazłem to. Okazuje się, że jest to kwestia typów danych SQL.
SomeStringProp
Kolumna w bazie danych varchar, ale zakłada, że EF NET rodzaje strun są nvarchars. Wynikowy proces tłumaczenia podczas zapytania DB o wykonanie porównania zajmuje dużo czasu. Myślę, że EF Prof trochę mnie tu sprowadził na manowce, dokładniejsza reprezentacja wykonywanego zapytania wyglądałaby następująco:SELECT [Extent1].[ID], [Extent1].[SomeStringProp], [Extent1].[SomeOtherProp], ... FROM [MyTable] as [Extent1] WHERE [Extent1].[SomeStringProp] = N'1234567890'
Zatem wynikowa poprawka polega na dodaniu adnotacji do modelu w pierwszej kolejności, wskazując poprawny typ danych SQL:
public class MyTable { ... [Column(TypeName="varchar")] public string SomeStringProp { get; set; } ... }
źródło
varchar
do wszystkiego i rzeczywiście na tym polegał problem. Zastanawiam się, czy mogę zrobić EDMX, aby wziąć pod uwagę varchar dla wszystkich kolumn łańcuchowych.Powodem spowolnienia moich zapytań wykonanych w EF było porównanie skalarów nieprzekraczających wartości zerowej ze skalarami dopuszczającymi wartość null:
long? userId = 10; // nullable scalar db.Table<Document>().Where(x => x.User.Id == userId).ToList() // or userId.Value ^^^^^^^^^ ^^^^^^ Type: long Type: long?
To zapytanie zajęło 35 sekund. Ale taka drobna refaktoryzacja:
long? userId = 10; long userIdValue = userId.Value; // I've done that only for the presentation pursposes db.Table<Document>().Where(x => x.User.Id == userIdValue).ToList() ^^^^^^^^^ ^^^^^^^^^^^ Type: long Type: long
daje niesamowite rezultaty. Ukończenie zajęło tylko 50 ms. Możliwe, że jest to błąd w EF.
źródło
Jeśli używasz płynnego mapowania, możesz użyć go
IsUnicode(false)
jako części konfiguracji, aby uzyskać ten sam efekt -http://msdn.microsoft.com/en-us/data/jj591617.aspx#1.9
http://msdn.microsoft.com/en-us/library/gg696416%28v=vs.103%29.aspx
źródło
Miałem ten sam problem (zapytanie jest szybkie, gdy jest wykonywane z menedżera SQL), ale po wykonaniu z EF limit czasu wygasa.
Okazuje się, że jednostka (która została utworzona z widoku) miała nieprawidłowe klucze encji. Tak więc jednostka miała zduplikowane wiersze z tymi samymi kluczami i myślę, że musiała grupować w tle.
źródło
Natknąłem się również na to ze złożonym zapytaniem ef. Jedną z poprawek, które zmniejszyło 6-sekundowe zapytanie ef do wygenerowanego przez nie drugiego zapytania sql, było wyłączenie leniwego ładowania.
Aby znaleźć to ustawienie (ef 6), przejdź do pliku .edmx i spójrz na Właściwości -> Generowanie kodu -> Lazy Loading Enabled. Ustawiono na fałsz.
Ogromna poprawa wydajności dla mnie.
źródło
Ja też miałem ten problem. Okazuje się, że winowajcą w moim przypadku było sniffowanie parametrów SQL-Server .
Pierwszą wskazówką, że mój problem był w rzeczywistości spowodowany podsłuchiwaniem parametrów, było to, że uruchomienie zapytania z ustawieniem „set arithabort off” lub „set arithabort on” skutkowało drastycznie różnymi czasami wykonywania w Management Studio. Dzieje się tak, ponieważ ADO.NET domyślnie używa „set arithabort off”, a Management Studio domyślnie „set arithabort on”. Pamięć podręczna planu kwerend przechowuje różne plany w zależności od tego parametru.
Wyłączyłem buforowanie planu zapytania dla zapytania, korzystając z rozwiązania, które możesz znaleźć tutaj .
źródło