Как следует из названия, у меня возникла проблема с первым запросом к базе данных SQL Server с использованием Entity Framework.
Я пытался найти ответ на разных сайтах, но никто, похоже, на самом деле не имеет решения для этого.
Я загружаю довольно много строк из базы данных, включая два отношения 0-много.
Тесты проводились в Visual Studio 2010 с использованием модели Entity Framework 4.0 и генератора POCO (нет большой разницы во времени между обычными объектами и объектами POCO). Я также использовал шаблон представлений T4 для предварительной компиляции представлений.
База данных была на SQL Server 2008.
То, что я действительно хотел бы знать, - то, почему первый запрос так намного медленнее, чем любые дополнительные запросы.
Я также хочу знать, можно ли что-то сделать, чтобы увеличить скорость первого запроса до точки, которая находится в допустимых пределах.
Это большой запрос, и мы можем получить другие запросы, которые даже больше, и понятно, что они могут быть немного медленными, но 30 секунд слишком медленные для пользователя, чтобы ждать, особенно когда наборы данных могут получить те же данные намного быстрее.
Я провел несколько временных тестов, чтобы попытаться выяснить, в чем заключается проблема, и я был немного удивлен, увидев, что, похоже, SQL Server медленно выполняет первый запрос.
Время было следующим:
Приложение для тестирования .NET:
SQL Profiler:
Окно SQL Server Query
Время в приложении измерялось с помощью класса 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 отправляет некоторые параметры вместе с первым запросом, который замедляет работу сервера.
Что касается компиляции запроса, то, насколько я помню, запрос компилируется при первом использовании, а это означает, что выполнение первого запроса займет еще больше времени.
Вторичные запросы будут быстрее, но скорость на вторичных запросах не является проблемой.
Я также провел тест, в котором я создал скомпилированный запрос как статический, чтобы он был скомпилирован для всех созданных контекстов.
Затем я создал контекст, запустил запрос, уничтожил контекст, создал новый и снова выполнил тот же запрос.
Разница была не так уж велика, всего несколько секунд, и в первый раз, когда я запускал запрос, он по-прежнему занимал столько времени, сколько и без предварительной компиляции.
Что касается генерации представления, мы уже реализуем это с помощью шаблонов T4.
Действительно ли ответ заключается в том, что EF работает, только если вы ничего не делаете, кроме самых простых запросов, которые возвращают только относительно небольшой объем данных?
У нас была такая же проблема в EF 5.0, и на сегодняшний день поверхностный поиск в Google не показывает достаточного ускорения.
По этой ссылке http://msdn.microsoft.com/en-us/library/cc853327(v=vs.100).aspx «Загрузка метаданных» требует умеренных затрат времени, но должна происходить только один раз для каждого домена приложения. Я не нашел никакой предварительной компиляции, как трюки для загрузки метаданных.
Обходное решение, которое мы реализовали, заключается в выполнении небольшого запроса в контексте в отдельном потоке при запуске приложения. Это загружает метаданные, это все еще занимает много времени (18-19 секунд в нашем случае), но приложение реагирует на загрузку. Также первая фактическая загрузка не занимает столько времени.
Обратите внимание, что в нашем контексте пользователь может провести в приложении 18–19 секунд, прежде чем потребуется выполнить вызов EF в ответ на его действия. Очевидно, что если это невозможно в вашем приложении, этот обходной путь может не обеспечить значительного увеличения скорости.