SQL Server- 저장된 절차가 갑자기 느려집니다
-
20-09-2019 - |
문제
어제는 일반적으로 1 초 미만으로 완료된 저장된 절차를 작성했습니다. 오늘은 약 18 초가 걸립니다. 나는 어제 문제에 도달했으며 저장된 절차를 떨어 뜨리고 다시 만들어 해결 된 것처럼 보였다. 오늘날 그 속임수는 작동하지 않는 것 같습니다. :(
흥미롭게도, 저장된 절차의 본문을 복사하고 간단한 쿼리로 실행하면 빠르게 완료됩니다. 속도를 늦추는 저장된 절차라는 사실 인 것 같습니다 ...!
문제가 무엇인지 아는 사람이 있습니까? 답변을 검색했지만 종종 쿼리 분석기를 통해 실행하는 것이 좋습니다. 그러나 지금은 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 및 위치에 공간 색인이 있습니다.
해결책
아, 쿼리 계획이 짜증나게 할 수 있습니까?
SP는 매개 변수에 따라 첫 번째 사용에 따라 컴파일 / 쿼리 LPAN이 결정됩니다. 따라서 첫 번째 호출의 매개 변수 (LPAN이 없을 때) 쿼리 계획을 결정합니다. 한 번의 Piont에서 나는 캐시에서 떨어지면 새로운 계획이 생성되었습니다.
다음에 느리게 실행되면 쿼리 분석기를 사용하여 호출하고 선택한 계획을 가져 와서 어떻게 보이는지 확인하십시오.
이것이라면 - 오프턴을 넣어 모든 통화에서 SP를 다시 컴파일하기 위해 (다시 컴파일 링).
다른 팁
매개 변수 스니핑 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
비슷한 문제가 있었고 인덱스와 관련이있었습니다.
그들을 재건하면 SP가 다시 빨리 달릴 수 있도록 도와줍니다.
솔루션을 찾았습니다 여기
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 '+@Database+';
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('+@DbID+', 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 IndexTempID=@IndexTempID
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 '+@Database+'; ALTER INDEX ' + @IndexName + N' ON ' + @SchemaName + N'.' + @TableName + N' REORGANIZE'
EXEC('USE '+@Database+'; ALTER INDEX ' + @IndexName + N' ON ' + @SchemaName + N'.' + @TableName + N' REORGANIZE')
END
ELSE
BEGIN --High fragmentation needs re-build
PRINT 'USE '+@Database+'; ALTER INDEX ' + @IndexName + N' ON ' + @SchemaName + N'.' + @TableName + N' REBUILD'
EXEC('USE '+@Database+'; 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