2010-03-17 15 views
6

He escrito un procedimiento almacenado que, ayer, normalmente se completaba en menos de un segundo. Hoy, toma alrededor de 18 segundos. También me encontré con el problema ayer, y pareció resolverse con DROP y volver a CREAR el procedimiento almacenado. Hoy, ese truco no parece estar funcionando. :(Servidor SQL: el procedimiento almacenado se vuelve lento

Curiosamente, si copio el cuerpo del procedimiento almacenado y ejecutarlo como una consulta directa se completa rápidamente. Parece ser el hecho de que es un procedimiento almacenado que está disminuyendo su velocidad ...!

¿Alguien sabe cuál podría ser el problema? He buscado las respuestas, pero a menudo recomiendan ejecutarlo a través del Analizador de consultas, pero no lo tengo - Estoy usando SQL Server 2008 Express por ahora.

El procedimiento almacenado es el siguiente;

 
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 tabla 'PDI' tiene un índice en MinLOD, MaxLOD y un índice espacial en Location.

Respuesta

3

Ah, ¿puede ser el plan de consulta una mierda?

Los SP se compilan/consultan lpan denegados en PRIMER USO, según los parámetros. Entonces, los parámetros de la primera llamada (cuando no hay presente lpan) determinan el plan de consulta. En un piont, me retiran del caché, se genera un nuevo plan.

La próxima vez que se ejecute lentamente, posiblemente haga una llamada utilizando el analizador de consultas y obtenga el plan seleccionado, y verifique cómo se ve.

si se trata de esto - poner en un opton para recompilar el SP en cada llamada (con recompilación).

+0

Esto bien puede ser la misma. Alteré el procedimiento almacenado para recompilar con cada llamada y parece (¡POR AHORA!) Haber acelerado las cosas de manera significativa. ¡Gracias! ¿Hay alguna manera de evitar la recompilación Y los malos planes de consulta? – Barguast

+0

No. Lo que puede hacer es volcar el procedimiento almacenado y usar sql dinámico ... para que los planes de consulta se regeneren en cada llamada. Este es un problema conocido (difícil de entender, no todos lo entienden, como KM) con procedimientos almacenados: a veces se convierten en planes de consulta REALMENTE malos. – TomTom

2

parámetro sniffing google it. probar esto, que "reasignar" los parámetros de entrada para las variables locales para evitar SQL Server de tratar de adivinar el plan de consulta en base a parámetros:

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

Lo intenté ya, y no pareció marcar la diferencia. Tendré que darle otra oportunidad. – Barguast

0

tuve un problema similar y se relacionó con índices.
Reconstruirlos ayuda a que el SP vuelva a funcionar rápidamente.

he encontrado la solución 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 
Cuestiones relacionadas