Другой план выполнения при выполнении оператора напрямую и из хранимой процедуры

StackOverflow https://stackoverflow.com/questions/421275

Вопрос

При разработке нового запроса на работе я написал его и профилировал в SQL Query Analyzer. Запрос выполнялся действительно хорошо без каких-либо сканирований таблицы, но когда я инкапсулировал его в хранимую процедуру, производительность была ужасной. Когда я посмотрел на план выполнения, я увидел, что SQL Server выбрал другой план, в котором вместо поиска по индексу в TableB использовалось сканирование таблицы (я был вынужден немного запутать имена таблиц и столбцов, но ни одна из логики запроса не использовалась). изменилось).

Вот запрос

SELECT     
    DATEADD(dd, 0, DATEDIFF(dd, 0, TableA.Created)) AS Day, 
    DATEPART(hh, TableA.Created) AS [Hour], 
    SUM(TableB.Quantity) AS Quantity, 
    SUM(TableB.Amount) AS Amount
FROM
    TableA
    INNER JOIN TableB ON TableA.BID = TableB.ID
WHERE     
    (TableA.ShopId = @ShopId)
GROUP BY 
    DATEADD(dd, 0, DATEDIFF(dd, 0, TableA.Created)), 
    DATEPART(hh, TableA.Created)
ORDER BY 
    DATEPART(hh, TableA.Created)

Когда я запускаю запрос " raw " Я получаю следующую статистику трассировки

Event Class         Duration  CPU  Reads Writes
SQL:StmtCompleted   75        41      7      0

И когда я запускаю запрос как сохраненный процесс, используя следующую команду

DECLARE @ShopId int
SELECT @ShopId = 1
EXEC spStats_GetSalesStatsByHour @ShopId

Я получаю следующую статистику трассировки

Event Class         Duration  CPU  Reads Writes
SQL:StmtCompleted   222       10     48      0

Я также получаю тот же результат, если я сохраняю запрос в nvarchar и выполняю его, используя sp_executesql следующим образом (он работает как sproc)

DECLARE @SQL nvarchar(2000)
SET @SQL = 'SELECT DATEADD(dd, ...'
exec sp_executesql @SQL

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

В настоящее время мы работаем на SQL Server 2000

Это было полезно?

Решение

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

alter procedure p_myproc (@p1 int) as
declare @p1_copy int;
set @p1_copy = @p1;

А затем используйте @ p1_copy в запросе. Кажется смешным, но это работает.

Проверьте мой недавний вопрос на ту же тему:

Почему оптимизатор SqlServer так запутывается с параметры?

Другие советы

Да, я видел это и в Oracle DB 11g - один и тот же запрос выполнялся быстро на 2 узлах db-сервера при запросе SQL, НО при вызове из пакета он буквально зависал!

пришлось очистить общий пул, чтобы получить идентичное поведение: причина, по которой выполнялось какое-то задание / сценарий, в котором старая копия была заблокирована в кеше / памяти библиотеки на одном узле с худшим планом выполнения.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top