La stessa stored procedure utilizza piani di esecuzione diversi determinanti differenti tempi di esecuzione.
Dimostreremo come una stored procedure, a parità di parametri passati, può essere eseguita in tempi diversi a seconda del riutilizzo o meno del piano di esecuzione creato per un determinato set di parametri
Consideriamo una semplice stored procedure usp_TABLETEST
create procedure [dbo].[usp_TABLETEST] @P1 int = null, @P2 int = null as begin select count(pk) from testtable where col1=@P1 and col2 = @P2 end
create procedure [dbo].[usp_TABLETEST] @P1 int = null, @P2 int = null
as
begin
select count(pk) from testtable where col1=@P1 and col2 = @P2
end
Eseguendo la stored procedure con i parametric @P1=1, @P2=20 , vedremo un piano di esecuzione utilizzante i due indici pk_testtable e idx1 e la letture di poche righe
set statistics time on set statistics profile on exec usp_TABLETEST 1,20
set statistics time on
set statistics profile on
exec usp_TABLETEST 1,20
Tempo di esecuzione:
SQL Server Execution Times: CPU time = 15 ms, elapsed time = 87 ms.
SQL Server Execution Times:
CPU time = 15 ms, elapsed time = 87 ms.
Eseguendo successivamente la stored procedure, con i parametri @P1=2, @P2=2, , vedremo un piano di esecuzione identico a quello precedente, ma effettuante numerose letture ed utilizzante un tempo di esecuzione superiore
set statistics time on set statistics profile on exec usp_TABLETEST 2,2
exec usp_TABLETEST 2,2
SQL Server Execution Times: CPU time = 1701 ms, elapsed time = 3648 ms.
CPU time = 1701 ms, elapsed time = 3648 ms.
Eseguendo la stored procedure con gli stessi parametri precedenti ma dopo aver pulito la procedure cache di Sql server , vedremo un nuovo piano di esecuzione, un numero di letture inferiore e conseguente beneficio sul tempo di esecuzione
Dbcc freeproccache set statistics time on set statistics profile on exec usp_TABLETEST 2,2
Dbcc freeproccache
SQL Server Execution Times: CPU time = 94 ms, elapsed time = 102 ms.
CPU time = 94 ms, elapsed time = 102 ms.
select sql_text.text, p.query_plan as exec_plan, max_elapsed_time, last_elapsed_time, min_elapsed_time, total_elapsed_time, qs.execution_count, creation_time, last_execution_time from sys.dm_exec_query_stats qs cross apply sys.dm_exec_sql_text(sql_handle) as sql_text cross apply sys.dm_exec_query_plan(plan_handle) as p where sql_text.text like '%nome stored procedure%'
select
sql_text.text,
p.query_plan as exec_plan,
max_elapsed_time,
last_elapsed_time,
min_elapsed_time,
total_elapsed_time,
qs.execution_count,
creation_time,
last_execution_time
from sys.dm_exec_query_stats qs
cross apply sys.dm_exec_sql_text(sql_handle) as sql_text
cross apply sys.dm_exec_query_plan(plan_handle) as p
where sql_text.text like '%nome stored procedure%'
Da notare la presenza dell'informazione relativa a "Missing Index"
Consiglio sempre di catturare le informazione sopra riportate in presenza e assenza di problemi di performance, confrontare i tempi di esecuzione, piani di esecuzione e i parametri utilizzati nella compilazione del piano, al fine di riprodurre il problema successivamente e capire quale tra le soluzioni sotto riportate potrebbero meglio adattarsi alla specifica situazione
Assicurarsi che le statistiche siano aggiornate, possibilmente tramite un fullscan (update statistics table_name with fullscan)
In questo modo , permetteremo a Sql server di avere le informazioni più recenti e complete possibile per creare un piano di esecuzione efficiente
Eseguire
Dbcc show_statistics (table_name , index name)
Verificare che Updated sia il più recente possibile e che Rows e RowsSampled siano uguali per avere le statistiche create su tutta la popolazione di dati della tabella
Di seguito alcune delle soluzioni adottate in problemi di questo tipo:
Raffaella Canobbio Senior Support Escalation Engineer Microsoft Enterprise SQL Support