Запрос выполняется быстро, но медленно в хранимой процедуре - PullRequest
34 голосов
/ 22 октября 2010

Я выполняю некоторые тесты с использованием профилировщика SQL 2005.

У меня есть хранимая процедура, которая просто запускает один SQL-запрос.

Когда я запускаю хранимую процедуру, она занимает много времени и выполняет 800 000 операций чтения с диска.

Когда я выполняю тот же запрос отдельно от хранимой процедуры, он выполняет 14 000 операций чтения с диска.

Я обнаружил, что если я выполню тот же запрос с OPTION (перекомпилировать), то потребуется 800 000 операций чтения с диска.

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

Может кто-нибудь пролить свет на это?

Я включил ARITHABORT. (Это решило аналогичную проблему для 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 contract_version.contract_id=@Contract_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

Вот скрипт, который я запускаю, который демонстрирует проблему:

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 @Contract_ID=@Contract_ID,@dt_From=@dt_From,@dt_To=@dt_To,@Last_Run_Date=@Last_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 contract_version.contract_id=@Contract_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 contract_version.contract_id=@Contract_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)

Ответы [ 6 ]

72 голосов
/ 22 октября 2010

ОК, у нас были подобные проблемы, как это раньше.

Способ, которым мы это исправили, заключался в создании локальных параметров внутри 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 , чтобы найти несколько полезных примеров, объяснений и исправлений.

6 голосов
/ 23 октября 2013

Как уже упоминали другие, это может быть проблемой «перехвата параметров». Попробуйте включить строку:

OPTION (RECOMPILE)

в конце вашего запроса SQL.

Здесь есть статья, объясняющая, что такое сниффинг параметров: http://blogs.technet.com/b/mdegre/archive/2012/03/19/what-is-parameter-sniffing.aspx

5 голосов
/ 22 октября 2010

Я думаю, это вызвано параметром сниффингом.

4 голосов
/ 28 сентября 2012

Проблема того, почему пакет выполняется вечно в хранимой процедуре SQL, но мгновенно запускается в SSMS, связана с анализом параметров SQL, особенно с параметрами datetime.

Есть несколько отличных статей по анализу параметров.

Вот один из них (я не писал, просто передавал).

http://www.sommarskog.se/query-plan-mysteries.html

3 голосов
/ 18 октября 2016

По моей проблеме я запустил:

exec sp_updatestats 

и это ускорило мой sp от 120 до 3 секунд. Более подробную информацию об обновлении статистики можно найти здесь https://msdn.microsoft.com/en-us/library/ms173804.aspx

2 голосов
/ 03 июня 2015

У меня сегодня тоже такая же проблема. Я сбросил и воссоздал SP, и это сработало. Это что-то с кешем SP, и при удалении SP кэшированный план был удален. Вы можете попробовать то же самое или использовать «DBCC FREEPROCCACHE» для удаления кэша.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...