Entity Framework query wolne, ale ten sam SQL w SqlQuery jest szybki

Widzę naprawdę dziwny perf związany z bardzo prostym zapytaniem przy użyciu kodu encji Framework-najpierw z. NET Framework w wersji 4. Zapytanie LINQ2Entities wygląda tak:

 context.MyTables.Where(m => m.SomeStringProp == stringVar);
Wykonanie tego zadania 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 uruchamia się niemal natychmiast po uruchomieniu przez Management Studio. Kiedy zmieniam kod C# na funkcję SqlQuery, działa on w ciągu 5-10 milisekund:

 context.MyTables.SqlQuery("SELECT [Extent1].[ID] ... WHERE [Extent1].[SomeStringProp] = @param", stringVar);

Więc dokładnie to samo SQL, wynikowe encje są śledzone w obu przypadkach, ale wild perf różnica między nimi. Co jest?

Author: Michael Sandler, 2013-04-02

7 answers

Znalazłem. Okazuje się, że jest to kwestia typów danych SQL. Kolumna SomeStringProp w bazie danych była varcharem, ale EF zakłada, że typy łańcuchowe. NET są nvarcharami. Wynikowy proces tłumaczenia podczas zapytania o DB, aby zrobić porównanie, zajmuje dużo czasu. Myślę, że EF Prof prowadził mnie trochę na manowce tutaj, dokładniejsze przedstawienie uruchamianego zapytania byłoby następujące:

 SELECT [Extent1].[ID], [Extent1].[SomeStringProp], [Extent1].[SomeOtherProp],
 ...
 FROM [MyTable] as [Extent1]
 WHERE [Extent1].[SomeStringProp] = N'1234567890'

Więc wynikową poprawką jest adnotacja modelu code-first, wskazująca na poprawny typ danych SQL:

public class MyTable
{
    ...

    [Column(TypeName="varchar")]
    public string SomeStringProp { get; set; }

    ...
}
 65
Author: Brian Sullivan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-02 19:39:05

Powodem spowolnienia moich zapytań wykonanych w EF było porównanie skalarów nie nullable z skalarami nullable:

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 taki malutki refaktoring:
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 50ms. Możliwe, że jest to błąd w EF.
 31
Author: cryss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-07 10:47:01

Jeśli używasz płynnego mapowania, możesz użyć 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

 6
Author: Matt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-25 20:36:01

Miałem ten sam problem (zapytanie jest szybkie przy wykonaniu z SQL managera) ale przy wykonaniu z EF upływa limit czasu.

Okazuje się, że encja (która została utworzona z widoku) miała błędne klucze encji. Tak więc encja miała zduplikowane wiersze z tymi samymi kluczami i myślę, że musiała grupować w tle.

 2
Author: Vladimir Gedgafov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-12 18:01:28

Natknąłem się również na to z złożonym zapytaniem ef. Jedną poprawką dla mnie, która zmniejszyła 6-sekundowe zapytanie ef do generowanego sub-sekundowego zapytania sql, było wyłączenie leniwego ładowania.

Aby znaleźć to ustawienie (ef 6) przejdź do.plik edmx i poszukaj w Properties - > Code generation - > lazy Loading Enabled. Ustawione na false.

Ogromna poprawa wydajności jak dla mnie.

 2
Author: user2622095,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-30 11:40:14

Możesz użyć następujących sztuczek, aby zamocować swoje zapytania -

  1. Ustaw ctx.Configuration.ProxyCreationEnabled Na false tuż przed uzyskaniem kontekstu.
  2. również, .Select(c => new {c.someproperty}) pobierze tylko wymagane dane, a nie całą masę.
Daj mi znać, jeśli to pomogło.
 1
Author: Rajesh Panda,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-16 20:30:43

Ja też miałem ten problem. Okazuje się, że winowajcą w moim przypadku był sniffing parametru SQL-Server .

Pierwszą wskazówką, że mój problem był w rzeczywistości spowodowany sniffingiem parametrów, było to, że uruchomienie zapytania z "set arithabort off" lub "set arithabort on" dało drastycznie różne czasy wykonania w Management Studio. Dzieje się tak dlatego, że ADO.NET domyślnie używa "set arithabort off", a Management Studio domyślnie "set arithabort on". Pamięć podręczna planu zapytań zachowuje różne plany w zależności od tego parametru.

Wyłączyłem buforowanie planu zapytań dla zapytania, z rozwiązaniem można znaleźć tutaj .

 1
Author: Oskar Sjöberg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-23 10:35:09