Запрос Entity Framework 4.1 выполняется слишком долго (5 секунд) - PullRequest
4 голосов
/ 17 ноября 2011

У меня есть DbContext (называемый "MyContext") с примерно 100 DbSets внутри него.

Среди классов домена у меня есть класс Document с 10 прямыми подклассами (такими как PurchaseOrder, RequestForQuotation и т. Д.).Иерархия отображается с помощью стратегии TPT.То есть в моей базе данных есть таблица Document с другими таблицами, такими как PurchaseOrder, RequestForQuotation для подклассов.

Когда я выполняю запрос, например:

Document document = myContext.Documents.First();

, запрос занимает 5секунд, независимо от того, запускаю ли я его в первый раз или позже.

Запрос типа:

Document document = myContext.Documents.Where(o => o.ID == 2);

также занимал много времени.

Это проблема сEF4.1 (если так, поможет ли EF4.2) или это проблема с кодами запроса?

Ответы [ 4 ]

3 голосов
/ 17 ноября 2011

Вы пытались использовать профиль SQL, чтобы увидеть, что на самом деле отправляется в БД? Возможно, в вашем документе слишком много объединений, для которых не установлена ​​отложенная загрузка, и поэтому запрос должен выполнять все объединения за один раз, возвращая слишком много столбцов. Попробуйте отправить простой запрос только с одним возвращаемым столбцом.

3 голосов
/ 17 ноября 2011

Как вы можете прочитать здесь , есть некоторые проблемы с производительностью, касающиеся TPT в EF.

EF Team анонсировала несколько исправлений в июнь 2011 CTP , включая оптимизацию запросов TPT, но они не включены в EF 4.2, как вы можете прочитать в комментариях к этому ответу .

В худшем случае эти исправления будут выпущены только в .NET 4.5. Я надеюсь, что это будет раньше ...

3 голосов
/ 17 ноября 2011

Я не уверен, что DbSet, предоставляемый первым кодом, фактически использует ObjectQuery, но вы можете попытаться вызвать для них метод .ToTraceString (), чтобы увидеть, какой SQL генерируется, например:

var query = myContext.Documents.Where(o => o.ID == 2);
Debug.WriteLine(query.ToTraceString());

Как только вы получите SQL, вы можете определить, является ли запрос или EF причиной задержки. В зависимости от сложности вашего базового класса запрос может включать в себя множество дополнительных столбцов, которых можно избежать с помощью проекции. Используя проекции, вы можете выполнить запрос следующим образом:

var query = from d in myContext.Documents
            where d.ID == 2
            select new
            {
                o.Id
            };

Это должно в основном выполнить запрос SELECT ID FROM Documents WHERE ID = 2, и вы можете измерить, сколько времени потребуется, чтобы получить дополнительную информацию. Конечно, спроектированный запрос может не соответствовать вашим потребностям, но он может привести вас на правильный путь. Если это все еще занимает до 5 секунд, вам следует изучить проблемы с производительностью самой базы данных, а не EF.

Обновление Очевидно, с помощью code-first вы можете использовать .ToString () вместо .ToTraceString (), спасибо Slauma за то, что обратили внимание.

1 голос
/ 02 января 2012

У меня только что была 5-секундная задержка в ExecuteFunction для хранимой процедуры, которая запускается мгновенно при вызове из SQL Management Studio.Я исправил это, переписав процедуру.

Похоже, что EF (и SSRS BTW) пытается сделать что-то вроде «подготовки» к сохраненному процессу и для некоторых (обычно сложных) процедур, которые могут занять очень много времени.

Быстрое и грязное решение - дублировать, а затем заменить параметры SP внутренними переменными:

create proc ListOrders(@CountryID int = 3, @MaxOrderCount int = 20)
as
declare @CountryID1 int, @MaxOrderCount1 int
set @CountryID1 = @CountryID
set @MaxOrderCount1 = @MaxOrderCount

select top (@MaxOrderCount1) *
from Orders
where CountryID = @CountryID1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...