2010-03-17 6 views
6

J'ai écrit une procédure stockée qui, hier, généralement terminée en moins d'une seconde. Aujourd'hui, cela prend environ 18 secondes. J'ai également rencontré le problème hier, et il semblait être résolu par DROPing et re-CREATE la procédure stockée. Aujourd'hui, cette astuce ne semble pas fonctionner. :(SQL Server - procédure stockée devient soudainement lente

Fait intéressant, si je copie le corps de la procédure stockée et l'exécuter comme une requête simple, il termine rapidement. Il semble être le fait que ce soit une procédure stockée qui est le ralentir ...!

Est-ce que quelqu'un sait quel est le problème? J'ai cherché des réponses, mais il est souvent recommandé de l'exécuter via l'Analyseur de requêtes, mais je ne l'ai pas - J'utilise SQL Server 2008 Express pour l'instant

La procédure stockée est la suivante:

 
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 table 'POI' a un index sur MinLOD, MaxLOD et un index spatial sur Location.

Répondre

3

Ah, est-ce que le plan de requête est nul?

Les SP sont compilés/interrogés à l'aide de FIRST USE - en fonction des paramètres. Ainsi, les paramètres du premier appel (quand aucun lpan n'est présent) déterminent le plan de requête. À un piont je tombe de la cache, nouveau plan généré.

La prochaine fois que la connexion sera lente, effectuez éventuellement un appel à l'aide de l'analyseur de requête et obtenez le plan sélectionné, puis vérifiez son apparence.

si c'est cela - mettre dans un opton pour recompiler le SP à chaque appel (avec recompiler).

+0

Cela pourrait bien l'être. J'ai modifié la procédure stockée pour la recompiler avec chaque appel et il semble (POUR MAINTENANT!) Avoir accéléré les choses de manière significative. Merci! Existe-t-il un moyen d'éviter la recompilation et les mauvais plans de requête? – Barguast

+0

Non. Ce que vous pouvez faire est vider la procédure stockée et utiliser SQL dynamique ... de sorte que les plans de requête sont régénérés chaque appel. C'est un problème connu (difficile à comprendre tous, comme KM) avec des procédures stockées - ils se transforment parfois en plans de requête VRAIMENT mauvais. – TomTom

2

paramètre reniflant google it. essayez ceci, qui « remap » les paramètres d'entrée aux variables locales pour empêcher SQL Server d'essayer de deviner le plan de requête en fonction des paramètres:

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

J'ai déjà essayé, et cela n'a pas semblé faire la différence. Je vais devoir recommencer. – Barguast

0

J'ai eu un problème similaire et il était lié avec des indices. Les reconstruire aide le SP à fonctionner à nouveau rapidement.

J'ai trouvé la solution 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 
Questions connexes