2010-03-17 6 views
6

Ho scritto una procedura memorizzata che, in genere, è stata completata in meno di un secondo. Oggi, ci vogliono circa 18 secondi. Mi sono imbattuto nel problema anche ieri, e mi è sembrato di risolvere DROPing e ri-CREARE la stored procedure. Oggi quel trucco non sembra funzionare. :(SQL Server - la procedura memorizzata diventa improvvisamente lenta

È interessante notare che, se copio il corpo della stored procedure ed eseguirlo come una query semplice che completa in modo rapido. Sembra essere il fatto che si tratta di una stored procedure che è rallentarla ...!

Qualcuno sa quale potrebbe essere il problema? Ho cercato le risposte, ma spesso si consiglia di eseguirlo tramite Query Analyzer, ma non ce l'ho - sto usando SQL Server 2008 Express per ora.

La stored procedure è la seguente:

 
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

La tabella 'POI' ha un indice su MinLOD, MaxLOD e un indice spaziale su Posizione.

risposta

3

Ah, può essere il piano di query fa schifo?

Gli SP vengono compilati/query lpan determinati su FIRST USE - in base ai parametri. Pertanto, i parametri della prima chiamata (quando non è presente lpan) determinano il piano di query. Ad un punto di vista mi viene lasciato cadere dalla cache, generato un nuovo piano.

La prossima volta che si esegue lentamente, è possibile effettuare una chiamata utilizzando l'analizzatore di query e ottenere il piano selezionato - e controllare come appare.

se è questo - inserire un opton per ricompilare l'SP su ogni chiamata (con ricompilare).

+0

Questo potrebbe essere essa. Ho modificato la procedura memorizzata per ricompilare con ogni chiamata e sembra (PER ORA!) Avere accelerato le cose in modo significativo. Grazie! C'è un modo per evitare la ricompilazione e piani di query non validi? – Barguast

+0

No. Quello che puoi fare è scaricare la stored procedure e usare sql dinamico ... in modo che i piani di query vengano rigenerati ogni chiamata. Questo è un problema noto (difficile non tutti sembrano capirlo, come KM) con stored procedure - a volte si trasformano in REALMENTE piani di query male. – TomTom

2

parametro sniffing google it. provare questo, che "rimappare" i parametri di input per le variabili locali per evitare che SQL Server da cercando di indovinare il piano di query sulla base di parametri:

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

L'ho provato già, e non sembrava fare la differenza. Dovrò fare un altro tentativo. – Barguast

0

Ho avuto un problema simile e si era collegato con gli indici.
Ricostruiscendoli aiuta l'SP a correre velocemente.

ho trovato la soluzione 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