2010-03-17 5 views
6

Я написал хранимую процедуру, которая вчера, как правило, завершалась в течение секунды. Сегодня это занимает около 18 секунд. Вчера я столкнулся с проблемой, и она, похоже, была решена с помощью DROPing и re-CREATEing хранимой процедуры. Сегодня этот трюк, похоже, не работает. :(SQL Server - хранимая процедура внезапно становится медленной

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

Кто-нибудь знает, в чем проблема? Я искал ответы, но часто они рекомендуют запускать его через Query Analyzer, но у меня его нет - я использую SQL Server 2008 Express на данный момент.

Сохраненная процедура заключается в следующем:

 
ALTER PROCEDURE [dbo].[spGetPOIs] 
    @lat1 float, 
    @lon1 float, 
    @lat2 float, 
    @lon2 float, 
    @minLOD tinyint, 
    @maxLOD tinyint, 
    @exact bit 
AS 
BEGIN 
    -- Create the query rectangle as a polygon 
    DECLARE @bounds geography; 
    SET @bounds = dbo.fnGetRectangleGeographyFromLatLons(@lat1, @lon1, @lat2, @lon2); 

    -- Perform the selection 
    if (@exact = 0) 
    BEGIN 
     SELECT [ID], [Name], [Type], [Data], [MinLOD], [MaxLOD], [Location].[Lat] AS [Latitude], [Location].[Long] AS [Longitude], [SourceID] 
     FROM [POIs] 
     WHERE 
      NOT ((@maxLOD [MaxLOD])) AND 
      (@bounds.Filter([Location]) = 1) 
    END 
    ELSE 
    BEGIN 
     SELECT [ID], [Name], [Type], [Data], [MinLOD], [MaxLOD], [Location].[Lat] AS [Latitude], [Location].[Long] AS [Longitude], [SourceID] 
     FROM [POIs] 
     WHERE 
      NOT ((@maxLOD [MaxLOD])) AND 
      (@bounds.STIntersects([Location]) = 1) 
    END 

END

Таблица «POI» имеет индекс для MinLOD, MaxLOD и пространственный индекс для местоположения.

ответ

3

Ах, может быть, план запроса сосет?

SP получить скомпилированный/запрос lpan, отфильтрованный при ПЕРВОМ ИСПОЛЬЗОВАНИИ - в зависимости от параметров. Таким образом, параметры первого вызова (когда нет lpan присутствует) определяют план запроса. На одном piont я выпадает из кеша, генерируется новый план.

В следующий раз, когда он работает медленно, возможно, позвоните с помощью анализатора запросов и получите выбранный план - и проверьте, как он выглядит.

Если это так - поставьте оппонент для перекомпиляции SP для каждого вызова (с перекомпиляцией).

+0

Это вполне может быть. Я изменил хранимую процедуру, чтобы перекомпилировать с каждым вызовом, и кажется (НАСЛЕДУЮ!), Чтобы значительно ускорить процесс. Благодаря! Есть ли способ избежать перекомпиляции и плохих планов запросов? – Barguast

+0

Нет. Что вы можете сделать, это сбросить хранимую процедуру и использовать динамический sql ... так что планы запросов восстанавливаются при каждом вызове. Это известная проблема (жесткие не все, похоже, понимают ее, как KM) с хранимыми процедурами - они иногда превращаются в ДЕЙСТВИТЕЛЬНО плохие планы запросов. – TomTom

2

параметр sniffing google it. попробовать это, который будет «переназначить» входные параметры для локальных переменных для предотвращения SQL Server от попыток угадать план запроса, основываясь на параметрах:

ALTER PROCEDURE [dbo].[spGetPOIs] 
    @lat1 float, 
    @lon1 float, 
    @lat2 float, 
    @lon2 float, 
    @minLOD tinyint, 
    @maxLOD tinyint, 
    @exact bit 
AS 
BEGIN 
DECLARE @X_lat1 float, 
    @X_lon1 float, 
    @X_lat2 float, 
    @X_lon2 float, 
    @X_minLOD tinyint, 
    @X_maxLOD tinyint, 
    @X_exact bit 



    -- Create the query rectangle as a polygon 
    DECLARE @bounds geography; 
    SET @bounds = dbo.fnGetRectangleGeographyFromLatLons(@X_lat1, @X_lon1, @lX_at2, @X_lon2); 

    -- Perform the selection 
    if (@exact = 0) 
    BEGIN 
     SELECT [ID], [Name], [Type], [Data], [MinLOD], [MaxLOD], [Location].[Lat] AS [Latitude], [Location].[Long] AS [Longitude], [SourceID] 
     FROM [POIs] 
     WHERE 
      NOT ((@X_maxLOD [MaxLOD])) AND 
      (@bounds.Filter([Location]) = 1) 
    END 
    ELSE 
    BEGIN 
     SELECT [ID], [Name], [Type], [Data], [MinLOD], [MaxLOD], [Location].[Lat] AS [Latitude], [Location].[Long] AS [Longitude], [SourceID] 
     FROM [POIs] 
     WHERE 
      NOT ((@X_maxLOD [MaxLOD])) AND 
      (@bounds.STIntersects([Location]) = 1) 
    END 

END 
+0

Я уже пробовал это, и, похоже, это не изменило ситуацию. Мне придется отдать это еще раз. – Barguast

0

У меня была аналогичная проблема, и это было связано с индексами.
Восстановление их помогает SP снова работать быстрее.

Я нашел решение here

USE master; 
GO 

CREATE PROC DatabaseReIndex(@Database VARCHAR(100)) AS 
BEGIN 
    DECLARE @DbID SMALLINT=DB_ID(@Database)--Get Database ID 
    IF EXISTS(SELECT * FROM tempdb.sys.objects WHERE name='Indexes') 
    BEGIN --Delete Temp Table if exists, then create 
    DROP TABLE TempDb.dbo.Indexes 
    END 

CREATE TABLE TempDb.dbo.Indexes(IndexTempID INT IDENTITY(1,1),SchemaName NVARCHAR(128),TableName NVARCHAR(128),IndexName NVARCHAR(128),IndexFrag FLOAT) 
EXEC ('USE '[email protected]+'; 
INSERT INTO TempDb.dbo.Indexes(TableName,SchemaName,IndexName,IndexFrag) 
SELECT OBJECT_NAME(ind.OBJECT_ID) AS TableName,sch.name,ind.name IndexName,indexstats.avg_fragmentation_in_percent 
FROM sys.dm_db_index_physical_stats('[email protected]+', NULL, NULL, NULL, NULL) indexstats 
INNER JOIN sys.indexes ind ON ind.object_id = indexstats.object_id AND ind.index_id = indexstats.index_id 
INNER JOIN sys.objects obj on obj.object_id=indexstats.object_id 
INNER JOIN sys.schemas as sch ON sch.schema_id = obj.schema_id 
WHERE indexstats.avg_fragmentation_in_percent > 10 AND indexstats.index_type_desc<>''HEAP'' 
ORDER BY indexstats.avg_fragmentation_in_percent DESC')--Get index data and fragmentation, set the percentage as high or low as you need 

DECLARE @IndexTempID BIGINT=0,@SchemaName NVARCHAR(128),@TableName NVARCHAR(128),@IndexName NVARCHAR(128),@IndexFrag FLOAT 
SELECT * FROM TempDb.dbo.Indexes --View your results, comment out if not needed... 

-- Loop through the indexes 
WHILE @IndexTempID IS NOT NULL 
    BEGIN 
    SELECT @SchemaName=SchemaName,@TableName=TableName,@IndexName=IndexName,@IndexFrag=IndexFrag FROM TempDb.dbo.Indexes WHERE [email protected] 
    IF @IndexName IS NOT NULL AND @SchemaName IS NOT NULL AND @TableName IS NOT NULL 
    BEGIN 
     IF @IndexFrag<30. 
     BEGIN --Low fragmentation can use re-organise, set at 30 as per most articles 
     PRINT 'USE '[email protected]+'; ALTER INDEX ' + @IndexName + N' ON ' + @SchemaName + N'.' + @TableName + N' REORGANIZE' 
     EXEC('USE '[email protected]+'; ALTER INDEX ' + @IndexName + N' ON ' + @SchemaName + N'.' + @TableName + N' REORGANIZE') 
     END 
    ELSE 
     BEGIN --High fragmentation needs re-build 
     PRINT 'USE '[email protected]+'; ALTER INDEX ' + @IndexName + N' ON ' + @SchemaName + N'.' + @TableName + N' REBUILD' 
     EXEC('USE '[email protected]+'; ALTER INDEX ' + @IndexName + N' ON ' + @SchemaName + N'.' + @TableName + N' REBUILD') 
     END 
    END 

    SET @IndexTempID=(SELECT MIN(IndexTempID) FROM TempDb.dbo.Indexes WHERE IndexTempID>@IndexTempID) 
    END 
END 

DROP TABLE TempDb.dbo.Indexes 

GO 
Смежные вопросы