Подтвердить что ты не робот

Entity Framework - первый запрос медленный

Как видно из названия, у меня возникла проблема с первым запросом к базе данных SQL Server с использованием Entity Framework.

Я пробовал искать ответ на разных сайтах, но никто, похоже, не имеет решения для этого.

Я загружаю довольно много строк из базы данных, включая два отношения 0-много.

Тесты были выполнены в Visual Studio 2010 с использованием модели Entity Framework 4.0 и генератора POCO (разница между синхронизациями между обычными объектами и объектами POCO невелика). Я также использовал шаблон T4 Views для предварительной компиляции представлений.

База данных находилась на SQL Server 2008.

Мне бы очень хотелось знать, почему первый запрос намного медленнее любых вторичных запросов.

Я также хочу знать, можно ли что-то сделать, чтобы увеличить скорость первого запроса до точки, где она находится в допустимых пределах.

Это большой запрос, и мы можем получить другие запросы, которые еще больше, и понятно, что они могут быть немного медленными, но 30 секунд слишком медленны, чтобы пользователь мог ждать, особенно когда наборы данных могут получать одни и те же данные. быстрее.

Я провел несколько тестов времени, чтобы попытаться выяснить, в чем проблема, и я был немного удивлен, увидев, что похоже на то, что SQL Server медленнее первого запроса.

Сроки были следующими:

Приложение для тестирования .NET:

  • Первый запрос: 29,6 секунд
  • Второй запрос: 3,2 секунды

SQL Profiler:

  • Первый запрос: 27 секунд
  • Второй запрос: 3,2 секунды

Окно запросов SQL Server

  • Первый запрос: 8 секунд
  • Второй запрос: 4 секунды

Сроки в приложении измерялись с помощью класса Stopwatch. Был запрограммирован только запрос и .ToList() был использован для выполнения запроса.

Сроки в SQL Server Profiler предназначены для тех же запросов, которые были выполнены в приложении, которое показывает, что приложение использует только 2,6 секунды для заполнения данных в объектах.

Последние 27 секунд используются для выполнения запроса на SQL Server.

Рассматривая вторичный запрос, тайминги одинаковы для приложения и SQL-сервера, но выполнение запроса на этот раз намного быстрее.

Я могу понять, почему приложение не использует какое-либо время, потому что нет новых строк, которые нужно преобразовать в объекты, но почему запрос намного быстрее, я бы ожидал несколько секунд из-за планов выполнения, но не 24 секунды.

Просто для тестирования я скопировал SQL, который Entity Framework генерирует и открывает новое окно запроса с отдельным подключением и выполняет запрос в нем.

Как вы видите, для первого запроса требуется 8 секунд и 4 секунды для второго.

Я надеюсь, что у кого-то есть предложения.

пс. Прошу прощения за стену текста:)

Редактировать 19-10-2010:
Вчера я сделал тест, который, похоже, поддерживает, что строки возвращаются последовательным образом. Это означает, что когда строка возвращается из базы данных, она немедленно материализуется (если она еще не существует в контексте), возвращается следующая строка и т.д.

Вот почему кажется, что запрос занимает много времени на сервере базы данных, потому что время материализации включено в тайминги профилировщика SQL Server.

Я не считаю, что это случай чтения SQL Server из жесткого диска. Медленный запрос выполняется каждый раз, когда в EF есть "первый запрос".

ех.

  • Запустите первый запрос с EF, оператор SQL будет медленнее, чем любой вторичный запрос
  • Утилизировать контекст/репозиторий
  • Создать новый контекст
  • Запустите тот же запрос, что и раньше (снова первый запрос выполняется медленно, а также оператор SQL)

Это похоже на то, что EF отправляет некоторые параметры вместе с первым запросом, который замедляет работу сервера.

Что касается компиляции запросов, как я помню, запрос скомпилирован в первый раз, когда он используется, что означает, что первый запрос займет еще больше времени.

Вторичные запросы будут быстрее, но скорость по вторичным запросам не является проблемой.

Я также проверил, где я создал скомпилированный запрос как статический, чтобы он был скомпилирован для всех созданных контекстов.

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

Разница была не такой большой, всего несколько секунд, и в первый раз, когда я запустил запрос, все еще продолжалось до тех пор, пока он не был предварительно скомпилирован.

Что касается генерации представлений, мы уже реализуем это с использованием шаблонов T4.

Действительно ли ответ, что EF работает, только если вы ничего не делаете, кроме простейших запросов, которые возвращают только относительно небольшой объем данных?

4b9b3361

Ответ 1

У нас была такая же проблема в EF 5.0, и на сегодняшний день поверхностный поиск Google не выявил достаточного ускорения.

В соответствии с этой ссылкой http://msdn.microsoft.com/en-us/library/cc853327(v=vs.100).aspx "Загрузка метаданных" несет умеренную временную стоимость, но она должна выполняться только один раз за AppDomain. Я не нашел предварительной компиляции, как трюки для загрузки метаданных.

Обходной путь, который мы реализовали, состоит в том, чтобы выполнить небольшой запрос в Контексте в отдельном потоке при запуске приложения. Это загружает метаданные, это по-прежнему занимает много времени (18-19 секунд в нашем случае), но приложение реагирует во время загрузки. Также первая фактическая нагрузка не занимает столько времени.

Обратите внимание, что в нашем контексте пользователь может потратить 18-19 секунд в приложении до того, как вызов EF необходимо будет выполнить в ответ на их действия. Очевидно, что если это невозможно в вашем приложении, эта работа может не обеспечить большую часть увеличения скорости.

Ответ 2

У меня была такая же проблема. И я использовал трюк, чтобы решить эту проблему. Поскольку инфраструктура Entity занимает немного больше времени при первом доступе, а затем кэширует часть результата в первый раз на этом уровне (сервер sql слишком кэширует результат отдельно). Таким образом, я получил доступ к инфраструктуре Entity для моего приложения, асинхронно. Это сработало для меня. И мое приложение стало более плавным.

На странице Global.asax

 protected void Application_Start()
    {

        Start(() =>
        {
            using (EF.DMEntities context = new EF.DMEntities())
            {
                context.DMUsers.FirstOrDefault();
            }
        });
    }
    private void Start(Action a)
    {
        a.BeginInvoke(null, null);
    } 

Ответ 3

Ну, многие вещи могут сделать запрос SQL Server медленнее при первом запуске. Однако большинство из них не принимают несколько секунд.

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

Что касается платформы Entity Framework, при первом запуске запроса она должна быть скомпилирована в SQL. Вы можете использовать тип CompiledQuery для предварительной компиляции запросов Entity Framework, чтобы выполнить эту работу заблаговременно, прежде чем конечный пользователь должен ее дождаться.

В очень большой модели поколение просмотров занимает некоторое время. Вместо этого вы можете переместить это, чтобы скомпилировать время. См. эту статью для получения дополнительных советов.

Ответ 4

У нас та же проблема. Это только с первым подходом Code. У нас есть около 1500 POCOs (+1500 картографических файлов POCO). Просто компиляция занимает около 1-2 минут. Метод Context.table.Add() занимает около 3-4 минут, но для первого объекта. Это как плохая шутка без решения. Эти 3-4 минуты, вероятно, являются своего рода EF "POCO transform". Одно ядро ​​процессора работает на 100%, и в профилировщике SQL ничего не происходит.

Использование первого подхода к базе данных (создание файла edmx xml) для тех же 1500 таблиц работает нормально. Это быстро, как ожидалось.

Пока нет решения. Возможно, EF6 решит это.

Ответ 5

Я просто наткнулся на это сообщение в своем поиске, чтобы улучшить время запуска EF. Поскольку у него действительно нет ответа, я добавлю свои выводы, чтобы другие люди могли воспользоваться им, если они наткнулись на этот пост тоже.

Обратите внимание, что я использую EF 6, и это решение применимо только для EF 6.

Дэвид Рот опубликовал статью в которой рассматривается проблема.

Микаэль Элиассон в своем ответе очень хорошо ответил на аналогичный вопрос:

  • Использование хранилища моделей кэшированных db
  • Создание предварительно скомпилированных представлений
  • Сгенерируйте предварительно скомпилированную версию сущностной схемы, используя n-gen, чтобы избежать джитта