Entity Framework 4.2 exec sp_executesql не использует индексы (sniffing параметров)
Я сталкиваюсь с некоторыми серьезными проблемами производительности с простыми SQL-запросами, сгенерированными Entity Framework (4.2), работающими с SQL Server 2008 R2. В некоторых ситуациях (но не во всех) EF использует следующий синтаксис:
exec sp_executesql 'DYNAMIC-SQL-QUERY-HERE', @param1...
В других ситуациях просто выполняется необработанный SQL с предоставленными параметрами, запеченными в запросе. Проблема, с которой я сталкиваюсь, заключается в том, что запросы, выполняемые с помощью sp_executesql, игнорируют все индексы в моих целевых таблицах, что приводит к чрезвычайно плохому выполнению запроса (подтверждается путем изучения плана выполнения в SSMS).
После небольшого исследования, похоже, проблема может быть вызвана "параметризацией". Если я добавлю подсказку запроса OPTION (RECOMPILE) следующим образом:
exec sp_executesql 'DYNAMIC-SQL-QUERY-HERE OPTION(RECOMPILE)', @param1...
Используются индексы в целевых таблицах, и запрос выполняется очень быстро. Я также попытался переключиться на флаг трассировки, используемый для отключения параметра sniffing (4136) в экземпляре базы данных (http://support.microsoft.com/kb/980653), однако, похоже, это не было любой эффект.
Это оставляет мне несколько вопросов:
- Есть ли способ добавить подсказку запроса OPTION (RECOMPILE) к SQL, сгенерированному Entity Framework?
- Есть ли способ предотвратить использование Entity Framework для использования exec sp_executesql, а вместо этого просто запустить необработанный SQL?
- Кто-нибудь еще сталкивается с этой проблемой? Любые другие подсказки/подсказки?
Дополнительная информация:
- Я перезапустил экземпляр базы данных через SSMS, однако я попробую перезапустить службу с консоли управления сервисами.
- Параметризация установлена на SIMPLE (is_parameterization_forced: 0)
- Оптимизация для рабочих нагрузок adhoc имеет следующие настройки:
- значение: 0
- минимум: 0
- максимум: 1
- value_in_use: 0
- is_dynamic: 1
- is_advanced: 1
Я также должен упомянуть, что если я перезапущу службу SQL Server через консоль управления сервисом ПОСЛЕ того, как включить флаг трассировки 4136 с ниже script, на самом деле очистит флаг трассировки... возможно, я должен делать это другим способ...
DBCC TRACEON(4136,-1)
Ответы
Ответ 1
В этот момент я бы рекомендовал:
Установите для параметра оптимизация для заданных рабочих нагрузок значение true.
EXEC sp_configure 'show advanced', 1;
GO
RECONFIGURE WITH OVERRIDE;
GO
EXEC sp_configure 'optimize for ad hoc', 1;
GO
RECONFIGURE WITH OVERRIDE
GO
EXEC sp_configure 'show advanced', 0;
GO
RECONFIGURE WITH OVERRIDE;
GO
Если через некоторое время этот параметр, похоже, не помог, только тогда я попробую дополнительную поддержку флага трассировки. Они обычно зарезервированы как последнее средство. Установите флаг трассировки с помощью командной строки через диспетчер конфигурации SQL Server, а не в окне запроса и используя глобальный флаг. См. http://msdn.microsoft.com/en-us/library/ms187329.aspx
Ответ 2
TL;DR
update statistics
У нас был запрос delete
с одним параметром (первичным ключом), которому потребовалось ~ 7 секунд для завершения при вызове через EF и sp_executesql
. Выполнение запроса вручную, с параметром, встроенным в первый аргумент в sp_executesql
, запустило запрос быстро (~ 0,2 секунды). Добавлена функция option (recompile)
. Конечно, эти две обходные пути недоступны для нас, поскольку они использовали EF.
Вероятно, из-за каскадных ограничений внешнего ключа, план выполнения для длинного запроса был, ммм..., огромным. Когда я посмотрел план выполнения в SSMS, я заметил, что стрелки между различными шагами в некоторых случаях были более широкими, чем другие, что, возможно, указывало на то, что SQL Server не мог принять правильные решения. Это заставило меня задуматься о статистике. Я посмотрел шаги в плане выполнения, чтобы увидеть, какая таблица была вовлечена в подозрительные шаги. Затем я запустил update statistics Table
для этой таблицы. Затем я повторно запустил плохой запрос. И я снова запустил его. И снова просто, чтобы убедиться. Это сработало. Наш перф вернулся к нормальной жизни. (Еще хуже, чем не sp_executesql
производительность, но эй!)
Оказалось, что это только проблема в нашей среде разработки. (И это была большая проблема, потому что это сделало наши тесты интеграции навсегда.) В нашей производственной среде у нас была работа, которая регулярно обновляла всю статистику.