В нашей базе данных SQL Server 2005 (протестировано с использованием Management Studio с DBCC FREEPROCCACHE
и
DBCC DROPCLEANBUFFERS
), следующий оператор работает быстро (время компиляции ~ 0,2 с, время выполнения ~ 0,1 с):
SELECT ... FROM ... WHERE a = 1 AND b = '' ...
Однако следующий оператор медленный (время компиляции ~ 0,2 с, 7-11 с время выполнения):
exec sp_executesql N'SELECT ... FROM ... WHERE a = @a AND b = @b ...', N'@a int, @b nvarchar(4000), ...', @a=1, @b=N'', ...
SQL Server выбирает другой план выполнения, хотя запросы совпадают. Это имеет смысл, поскольку в первом случае SQL Server имеет фактические значения a
, b
и все другие доступные параметры и может использовать статистику для создания лучшего плана. По-видимому, план запроса для конкретных значений параметров на намного лучше , чем общий, и определенно перевешивает любое преимущество в производительности "кэширование плана запроса".
Теперь мой вопрос: ADO.NET всегда использует второй параметр (sp_executesql) при выполнении параметризованных запросов, который обычно имеет смысл (кэширование плана запросов и т. Д.). В нашем случае, однако, это убивает производительность. Так есть ли какой-нибудь способ
- заставляет ADO.NET использовать что-то отличное от
sp_executesql
(то есть то, что анализатор запросов SQL Server учитывает фактические значения параметров) ИЛИ
- заставляет SQL Server пересчитать план запроса SQL, переданного в
sp_executesql
, принимая во внимание значения параметров ?
И, пожалуйста, не говорите мне, что я должен вернуться к некрасивому, старому, опасному sql = "WHERE b = " + quoteAndEscape(parameterB)
...
Помещение SQL в хранимую процедуру не имеет значения (медленно, с WITH RECOMPILE
и без него). Я не публиковал фактическую статистику SQL, поскольку она довольно сложна (объединяет несколько таблиц, включая подвыборы и агрегацию).