Запрос выполняется быстро, но работает медленнее в хранимой процедуре
Я делаю некоторые тесты, используя профилировщик SQL 2005.
У меня есть хранимая процедура, которая просто запускает один SQL-запрос.
Когда я запускаю хранимую процедуру, она занимает много времени и выполняет 800 000 операций чтения на диске.
Когда я запускаю один и тот же запрос отдельно от хранимой процедуры, он читает 14 000 дисков.
Я обнаружил, что если я запускаю тот же запрос с OPTION (перекомпилируем), он берет 800 000 дисков.
Из этого я делаю (возможно ошибочное) предположение, что хранимая процедура перекомпилируется каждый раз и вызывает проблему.
Может ли кто-нибудь пролить свет на это?
Я установил ARITHABORT ON. (Это разрешило аналогичную проблему в stackoverflow, но не решило мое)
Вот вся хранимая процедура:
CREATE PROCEDURE [dbo].[GET_IF_SETTLEMENT_ADJUSTMENT_REQUIRED]
@Contract_ID int,
@dt_From smalldatetime,
@dt_To smalldatetime,
@Last_Run_Date datetime
AS
BEGIN
DECLARE @rv int
SELECT @rv = (CASE WHEN EXISTS
(
select * from
view_contract_version_last_volume_update
inner join contract_version
on contract_version.contract_version_id = view_contract_version_last_volume_update.contract_version_id
where [email protected]_ID
and volume_date >= @dt_From
and volume_date < @dt_To
and last_write_date > @Last_Run_Date
)
THEN 1 else 0 end)
-- Note that we are RETURNING a value rather than SELECTING it.
-- This means we can invoke this function from other stored procedures
return @rv
END
Здесь выполняется script, который демонстрирует проблему:
DECLARE
@Contract_ID INT,
@dt_From smalldatetime,
@dt_To smalldatetime,
@Last_Run_Date datetime,
@rv int
SET @Contract_ID=38
SET @dt_From='2010-09-01'
SET @dt_To='2010-10-01'
SET @Last_Run_Date='2010-10-08 10:59:59:070'
-- This takes over fifteen seconds
exec GET_IF_SETTLEMENT_ADJUSTMENT_REQUIRED @[email protected]_ID,@[email protected]_From,@[email protected]_To,@[email protected]_Run_Date
-- This takes less than one second!
SELECT @rv = (CASE WHEN EXISTS
(
select * from
view_contract_version_last_volume_update
inner join contract_version
on contract_version.contract_version_id = view_contract_version_last_volume_update.contract_version_id
where [email protected]_ID
and volume_date >= @dt_From
and volume_date < @dt_To
and last_write_date > @Last_Run_Date
)
THEN 1 else 0 end)
-- With recompile option. Takes 15 seconds again!
SELECT @rv = (CASE WHEN EXISTS
(
select * from
view_contract_version_last_volume_update
inner join contract_version
on contract_version.contract_version_id = view_contract_version_last_volume_update.contract_version_id
where [email protected]_ID
and volume_date >= @dt_From
and volume_date < @dt_To
and last_write_date > @Last_Run_Date
)
THEN 1 else 0 end) OPTION(recompile)
Ответы
Ответ 1
Хорошо, раньше у нас были подобные проблемы.
Как мы это исправили, это сделать локальные параметры внутри SP, так что
DECLARE @LOCAL_Contract_ID int,
@LOCAL_dt_From smalldatetime,
@LOCAL_dt_To smalldatetime,
@LOCAL_Last_Run_Date datetime
SELECT @LOCAL_Contract_ID = @Contract_ID,
@LOCAL_dt_From = @dt_From,
@LOCAL_dt_To = @dt_To,
@LOCAL_Last_Run_Date = @Last_Run_Date
Затем мы используем локальные параметры внутри SP, а не параметры, которые были переданы.
Это обычно исправляло проблему для нас.
Мы полагаем, что это связано с параметрическим обнюхиванием, но у вас нет никаких доказательств, извините... X -)
EDIT:
Посмотрите Различные подходы к исправлению SQL Server Parameter Sniffing для некоторых проницательных примеров, объяснений и исправлений.
Ответ 2
Я предполагаю, что это вызвано параметром sniffing.
Ответ 3
Вопрос о том, почему пакет навсегда запускается в хранимой процедуре SQL, но мгновенно запускается в SSMS, имеет отношение к sniffing параметров SQL, особенно с параметрами datetime.
Есть несколько отличных статей о параметрическом обнюхивании.
Здесь один из них (я не писал его, просто передал его).
http://www.sommarskog.se/query-plan-mysteries.html
Ответ 4
Как уже упоминалось, это может быть проблема с параметрическим обнюхиванием. Попробуйте включить строку:
OPTION (RECOMPILE)
в конце вашего SQL-запроса.
Здесь есть статья, объясняющая, какой параметр нюхает: http://blogs.technet.com/b/mdegre/archive/2012/03/19/what-is-parameter-sniffing.aspx
Ответ 5
В моей проблеме я запустил:
exec sp_updatestats
и это ускорит мой sp от 120s до 3s. Более подробную информацию об обновлении статистики можно найти здесь https://msdn.microsoft.com/en-us/library/ms173804.aspx
Ответ 6
У меня тоже такая же проблема сегодня. Я сбросил и воссоздал SP, и это сработало. Это что-то с тайником SP, и когда вы сбросили SP, кешированный план был удален. Вы можете попробовать то же самое или использовать "DBCC FREEPROCCACHE" для удаления кеша.