Ho una procedura memorizzata che funziona terribilmente. Quando dichiaro una variabile, imposta il suo valore e quindi la utilizzo nella clausola where, l'istruzione impiega più di un'ora per essere eseguita. Quando faccio un duro codice delle variabili nella clausola where viene eseguito in meno di un secondo.Il parametro non esegue altrettanto bene la codifica hard del valore
Ho iniziato a esaminare cosa c'era di sbagliato con i piani di esecuzione. Sembra che quando provo a passarle alcune variabili dichiarate, il piano di esecuzione esegue il crashare di una corrispondenza hash perché seleziona i valori da una vista che utilizza UNION e un'espressione di tabella comune.
/************* Begin of Stored Procedure ***************/ CREATE PROCEDURE GetFruit @ColorId bigint, @SeasionId bigint WITH RECOMPILE AS BEGIN SELECT A.Name FROM [Apple_View] A /* This is the view down below */ INNER JOIN [Fruit] F ON (F.ColorId = @ColorId AND A.FruitId = F.FruitId) WHERE (A.ColorId = @ColorId AND A.SeasonId = @SeasonId) END /************* End of Stored Procedure ***************/ /************* Begin of View ***************/ WITH Fruits (FruitId, ColorId, SeasonId) AS ( -- Anchor member SELECT F.FruitId ,F.ColorId ,F.SeasonId FROM (( SELECT DISTINCT EF.FruitId ,EF.ColorId ,EF.SeasonId ,EF.ParentFruitId FROM ExoticFruit EF INNER JOIN Fruit FR ON FR.FruitId = EF.FruitId UNION SELECT DISTINCT SF.FruitId ,SF.ColorId ,SF.SeasonId ,SF.ParentFruitId FROM StinkyFruit SF INNER JOIN Fruit FR ON FR.FruitId = SF.FruitId UNION SELECT DISTINCT CF.FruitId ,CF.ColorId ,CF.SeasonId ,CF.ParentFruitId FROM CrazyFruit CF INNER JOIN Fruit FR ON FR.FruitId = CF.FruitId )) f UNION ALL -- Recursive Parent Fruit SELECT FS.FruitId ,FS.ColorId ,FS.SeasonId ,FS.ParentFruitId FROM Fruits FS INNER JOIN MasterFruit MF ON MF.[ParentFruitId] = fs.[FruitId] ) SELECT DISTINCT FS.FruitId ,FS.ColorId ,FS.SeasonId FROM Fruits FS /************* End of View ***************/ /* To Execute */ EXEC GetFruit 1,3
Se eseguire la stored procedure utilizzando i valori impostati ci vuole più di un'ora e qui è il piano di esecuzione.
Se eseguire la stored procedure di rimuovere i valori di dichiarare e SET e basta impostare la clausola Dove la seguente dichiarazione viene eseguito in meno di un secondo e qui è il piano di esecuzione:
WHERE(A.ColorId = 1 AND A.SeasonId = 3)
Si noti come le variabili codificate hard utilizzano l'indicizzazione mentre il primo utilizza un hash. Perché? Perché i valori hard coded nella clausola where funzionano in modo diverso rispetto alle variabili dichiarate?
------- questo è quello che finalmente effettuato con l'ausilio di @ user1166147 ------
ho cambiato la stored procedure da utilizzare sp_executesql.
CREATE PROCEDURE GetFruit @ColorId bigint, @SeasionId bigint WITH RECOMPILE AS BEGIN DECLARE @SelectString nvarchar(max) SET @SelectString = N'SELECT A.Name FROM [Apple_View] A /* This is the view down below */ INNER JOIN [Fruit] F ON (F.ColorId = @ColorId AND A.FruitId = F.FruitId) WHERE (A.ColorId = ' + CONVERT(NVARCHAR(MAX), @ColorId) + ' AND A.SeasonId = ' + CONVERT(NVARCHAR(MAX), @SeasonId) + ')' EXEC sp_executesql @SelectString END
Avete controllato per assicurarsi che i tipi di dati dei parametri corrispondono ai tipi di dati di colonna? – HackedByChinese
Queste sono variabili non parametri. SQL Server non esegue lo sniffing delle variabili, pertanto le stime di selettività verranno prese in considerazione. Cosa succede se si aggiunge 'OPTION (RECOMPILE)'? –
utilizza l'opzione ricompilare. C'è qualcosa chiamato sniffing dei parametri in cui SQL Server genera un piano di query diverso a seconda dei valori di input – praveen