ОБНОВЛЕНИЕ 3: согласно это объявление, это было рассмотрено командой EF в EF6 alpha 2.
ОБНОВЛЕНИЕ 2: я создал предложение по устранению этой проблемы. Чтобы проголосовать за него, перейдите сюда.
Рассмотрим базу данных SQL с одной очень простой таблицей.
CREATE TABLE Main (Id INT PRIMARY KEY)
Я заполняю таблицу 10 000 записей.
WITH Numbers AS
(
SELECT 1 AS Id
UNION ALL
SELECT Id + 1 AS Id FROM Numbers WHERE Id <= 10000
)
INSERT Main (Id)
SELECT Id FROM Numbers
OPTION (MAXRECURSION 0)
Я создаю модель EF для таблицы и запускаю следующий запрос в LINQPad (я использую режим «Выражения C#», поэтому LINQPad не создает дамп автоматически).
var rows =
Main
.ToArray();
Время выполнения ~0,07 секунды. Теперь я добавляю оператор Contains и повторно запускаю запрос.
var ids = Main.Select(a => a.Id).ToArray();
var rows =
Main
.Where (a => ids.Contains(a.Id))
.ToArray();
Время выполнения для этого случая составляет 20,14 секунды (в 288 раз медленнее)!
Сначала я подозревал, что T-SQL, сгенерированный для запроса, выполнялся дольше, поэтому я попытался вырезать и вставить его из панели SQL LINQPad в SQL Server Management Studio.
SET NOCOUNT ON
SET STATISTICS TIME ON
SELECT
[Extent1].[Id] AS [Id]
FROM [dbo].[Primary] AS [Extent1]
WHERE [Extent1].[Id] IN (1,2,3,4,5,6,7,8,...
И результат был
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 88 ms.
Затем я подозревал, что проблема вызвана LINQPad, но производительность одинакова, запускаю ли я его в LINQPad или в консольном приложении.
Итак, похоже, что проблема где-то внутри Entity Framework.
Я делаю что-то не так здесь? Это критическая по времени часть моего кода, так что я могу сделать, чтобы повысить производительность?
Я использую Entity Framework 4.1 и Sql Server 2008 R2.
ОБНОВЛЕНИЕ 1:
В приведенном ниже обсуждении возник ряд вопросов о том, произошла ли задержка во время построения исходного запроса EF или во время анализа полученных данных. Чтобы проверить это, я запустил следующий код:
var ids = Main.Select(a => a.Id).ToArray();
var rows =
(ObjectQuery<MainRow>)
Main
.Where (a => ids.Contains(a.Id));
var sql = rows.ToTraceString();
что заставляет EF генерировать запрос, не выполняя его для базы данных. В результате для выполнения этого кода потребовалось ~20 секунд, так что кажется, что почти все время уходит на построение исходного запроса.
CompiledQuery спешит на помощь? Не так быстро... CompiledQuery требует, чтобы параметры, передаваемые в запрос, были фундаментальными типами (int, string, float и т. д.). Он не будет принимать массивы или IEnumerable, поэтому я не могу использовать его для списка идентификаторов.
var qry = Main.Where (a => ids.Contains(a.Id)); var rows = qry.ToArray();
посмотреть, какая часть запроса занимает время? - person Andrew Cooper   schedule 26.10.201110 <= ids <= 500
? - person Kris Ivanov   schedule 26.10.2011parent._recompileRequired = () => true;
происходит для всех запросов, содержащих параметр IEnumerable‹T›. Бу! - person jocull   schedule 15.11.2013