Domanda

Durante lo sviluppo di una nuova query al lavoro, l'ho scritta e profilata in SQL Query Analyzer. La query ha funzionato davvero bene senza scansioni di tabelle ma quando l'ho incapsulata in una procedura memorizzata, le prestazioni sono state orribili. Quando ho esaminato il piano di esecuzione ho visto che SQL Server ha scelto un piano diverso che utilizzava una scansione di tabella anziché una ricerca di indice su TableB (sono stato costretto a offuscare un po 'i nomi di tabella e colonna ma nessuna della logica della query è cambiato).

Ecco la query

SELECT     
    DATEADD(dd, 0, DATEDIFF(dd, 0, TableA.Created)) AS Day, 
    DATEPART(hh, TableA.Created) AS [Hour], 
    SUM(TableB.Quantity) AS Quantity, 
    SUM(TableB.Amount) AS Amount
FROM
    TableA
    INNER JOIN TableB ON TableA.BID = TableB.ID
WHERE     
    (TableA.ShopId = @ShopId)
GROUP BY 
    DATEADD(dd, 0, DATEDIFF(dd, 0, TableA.Created)), 
    DATEPART(hh, TableA.Created)
ORDER BY 
    DATEPART(hh, TableA.Created)

Quando eseguo la query " raw " Ottengo le seguenti statistiche di traccia

Event Class         Duration  CPU  Reads Writes
SQL:StmtCompleted   75        41      7      0

E quando eseguo la query come proc memorizzato usando il seguente comando

DECLARE @ShopId int
SELECT @ShopId = 1
EXEC spStats_GetSalesStatsByHour @ShopId

Ottengo le seguenti statistiche di traccia

Event Class         Duration  CPU  Reads Writes
SQL:StmtCompleted   222       10     48      0

Ottengo lo stesso risultato anche se memorizzo la query in un nvarchar ed eseguo usando sp_executesql in questo modo (funziona come lo sproc)

DECLARE @SQL nvarchar(2000)
SET @SQL = 'SELECT DATEADD(dd, ...'
exec sp_executesql @SQL

La procedura memorizzata non contiene nulla ad eccezione dell'istruzione select sopra. Cosa indurrebbe SQL Server a scegliere un piano di esecuzione inferiore solo perché l'istruzione viene eseguita come procedura memorizzata?

Attualmente siamo in esecuzione su SQL Server 2000

È stato utile?

Soluzione

In genere ciò ha a che fare con lo sniffing dei parametri. Può essere molto frustrante da affrontare. A volte può essere risolto ricompilando la procedura memorizzata, e talvolta è anche possibile utilizzare una variabile duplicata all'interno della procedura memorizzata in questo modo:

alter procedure p_myproc (@p1 int) as
declare @p1_copy int;
set @p1_copy = @p1;

E quindi utilizzare @ p1_copy nella query. Sembra ridicolo ma funziona.

Controlla la mia recente domanda sullo stesso argomento:

Perché l'ottimizzatore SqlServer viene così confuso con parametri?

Altri suggerimenti

Sì - l'avevo visto anche su Oracle DB 11g - la stessa query è stata eseguita rapidamente su 2 nodi del server db al prompt SQL MA quando chiamato dal pacchetto ha letteralmente riagganciato!

ha dovuto cancellare il pool condiviso per ottenere un comportamento identico: motivo per cui era in esecuzione un lavoro / script che aveva una copia precedente bloccata nella cache / memoria della libreria su un nodo con piano di esecuzione inferiore.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top