ОБНОВЛЕНИЕ
Я полностью пересматриваю этот ответ из-за некоторых недавних событий.
Из-за того, что команда Entity Framework в Microsoft пыталась дублировать мою проблему, я вернулся и повторил свои шаги, чтобы лучше помочь сузить проблему.Прошло много времени с тех пор, как я задал этот вопрос, и теперь я понимаю вещи намного лучше, чем тогда.
Вместо того, чтобы вернуться и попытаться запустить какой-то очень старый код, я решил начать с нуля с простого тестапроект.Я собрал простую базу данных с двумя таблицами и сопоставил их с файлом конструктора EF 4.0.
Это сгенерировало строку подключения следующим образом:
<add name="EFTestEntities" connectionString="metadata=res://*/Entities.csdl|res://*/Entities.ssdl|res://*/Entities.msl;provider=System.Data.SqlClient;provider connection string="data source=.\sqlexpress;initial catalog=EFTest;integrated security=True;multipleactiveresultsets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
Затем я заполнил базу данных 1000 строк.тестовых тем и 10 строк ответов для каждой темы.Как только я заработал эту работу, я рассчитал очень простой запрос, довольно похожий на тот, что был в моем основном вопросе.Затем я продублировал тестовый проект и изменил его, используя расширение Entity Framework Power Tools для генерации объектов моей модели и DbContext.Единственное, что я изменил, это строку подключения, чтобы удалить метаданные, на которые ссылаются, когда в проекте есть файл конструктора, поэтому он выглядел так:
<add name="EFTestContext" providerName="System.Data.SqlClient" connectionString="Data Source=.\sqlexpress;Initial Catalog=EFTest;Integrated Security=True;Pooling=False" />
Затем я выполнил точно такой же запрос, как и яс конструктором.
Разницы во времени запросов не было, за исключением небольшого дополнительного времени, которое требуется первому коду для создания метаданных отображения.После этого начального запроса две версии EF выполнялись практически одинаково.Я собирался решить проблему как не воспроизводимую, но затем я заметил, что сделал что-то ужасное в этом вопросе.Я позвонил .AsEnumerable()
до моих запросов.Если вы еще не знаете, что это делает, это приведет к тому, что вся коллекция сущностей будет извлечена в память, а затем запрос будет применяться там как LINQ-to-Objects, а не LINQ-to-Entities.
Это означает, что я засосал всю таблицу в память, а затем делал там LINQ.В тех случаях, когда SQL-сервер находится на той же машине, что и ваш веб-сайт, вы можете не заметить разницы, но во многих случаях это будет огромной проблемой.В моем случае это действительно вызывало потерю производительности.
Я вернулся к своим тестам и запустил их с .AsEnumerable()
, помещенным перед запросами.
Теперь я ожидал, что время будет медленнеепоскольку мои запросы LINQ не переводились в деревья выражений и не выполнялись в базе данных.Тем не менее, похоже, я воспроизвел проблему в своем вопросе.Версия только для кода возвращается намного медленнее.Это на самом деле довольно странно, потому что они оба должны работать одинаково.Я не удивлен, что они выполняются медленнее, чем когда запросы были против IQueryable, но теперь, когда они работают с IEnumerable, между ними есть большая разница.Мне удалось увеличить разницу между ними, добавив в таблицу все больше и больше данных.
Я добавил еще 5000 тем в базу данных, по 30 ответов на каждую тему.Таким образом, в настоящее время в общей сложности 6000 строк тем и 165000 строк ответов.Сначала я выполнил запрос с соответствующими LINQ-to-Entities:
Как видите, все равно разницы нет.Затем я запустил запросы с LINQ-to-Objects, используя .AsEnumerable()
.
. Я остановил его после трех запросов, потому что ожидание около двух минут на запрос было мучительным.Кажется, я не могу выдать 3x как медленную проблему, которую я показываю в своем вопросе, но только код значительно медленнее.Подход EDMX занимает всего две минуты, чтобы выполнить один запрос, в то время как подход, основанный только на коде, последовательно занимает более двух минут.