Eu tenho um procedimento armazenado que está produzindo planos ligeiramente diferentes para parâmetros diferentes. Eu esperaria que ele usasse o mesmo plano que foi gerado quando foi executado pela primeira vez.
CREATE TABLE myTable (
ID INT IDENTITY(1,1) PRIMARY KEY,
Column1 VARCHAR(50),
Column2 VARCHAR(50),
Column3 VARCHAR(50),
Column4 VARCHAR(50),
Column5 VARCHAR(50),
Column6 VARCHAR(50),
Column7 VARCHAR(50),
Column8 VARCHAR(50),
Column9 VARCHAR(50),
Column10 VARCHAR(50)
)
DECLARE @i INT = 1
DECLARE @j INT = 1
DECLARE @distinct_value_count INT = 20
DECLARE @distinct_value_count_with_more_rows INT = 3
DECLARE @rows_per_distinct_value INT = (20000 - (@distinct_value_count_with_more_rows * 2000)) / (@distinct_value_count - @distinct_value_count_with_more_rows)
WHILE @i <= @distinct_value_count
BEGIN
DECLARE @current_rows_per_value INT = @rows_per_distinct_value
IF @i <= @distinct_value_count_with_more_rows
BEGIN
SET @current_rows_per_value = @rows_per_distinct_value + 2000
END
SET @j = 1
WHILE @j <= @current_rows_per_value
BEGIN
INSERT INTO myTable (Column1, Column2, Column3, Column4, Column5, Column6, Column7, Column8, Column9, Column10)
VALUES ('Value' + CAST(@i AS VARCHAR(2)),
'Value' + CAST(@j AS VARCHAR(5)),
'Value' + CAST(@j + 1 AS VARCHAR(5)),
'Value' + CAST(@j + 2 AS VARCHAR(5)),
'Value' + CAST(@j + 3 AS VARCHAR(5)),
'Value' + CAST(@j + 4 AS VARCHAR(5)),
'Value' + CAST(@j + 5 AS VARCHAR(5)),
'Value' + CAST(@j + 6 AS VARCHAR(5)),
'Value' + CAST(@j + 7 AS VARCHAR(5)),
'Value' + CAST(@j + 8 AS VARCHAR(5)))
SET @j = @j + 1
END
SET @i = @i + 1
END
Create NonClustered Index Idx_col on MyTable(Column1)
sp_recompile 'dbo.MyTable'
Create or Alter Procedure dbo.tmp_testProc(
@inValue VarChar(50)
)
As
Begin
Set NoCount On
Select Id
Into #tmpCol
From MyTable
Where Column1 = @inValue
Select t.*
From MyTable t
Join #tmpCol tmp
On t.Id = tmp.Id
Order by t.Id
End
--Scenario 1
exec dbo.tmp_testProc @inValue = 'Value1'
--Scenario 2
exec dbo.tmp_testProc @inValue = 'Value5'
Estou executando o procedimento armazenado com valor de parâmetro = 'Value1'
para a primeira execução e depois com 'Value5'
. Aqui estão os planos de execução para ambos os cenários:
Plano de Execução do Cenário 1 : https://www.brentozar.com/pastetheplan/?id=r1H-3HONh
Plano de Execução do Cenário 2 : https://www.brentozar.com/pastetheplan/?id=r1p42SOE3
Previ que o segundo cenário empregaria o mesmo plano do primeiro, mas observei que o plano é diferente. Fiquei com a impressão de que o otimizador reutiliza o mesmo plano gerado para o parâmetro inicial definido para todas as execuções subsequentes. Portanto, não tenho certeza do motivo pelo qual o otimizador está criando planos diferentes nessa instância. Agradeceria qualquer esclarecimento sobre este assunto. Obrigado pela sua ajuda.
Meu primeiro pensamento foi que você está executando o SQL Server 2022 e atingiu um novo recurso chamado Parameter Sensitive Plan Optimization , onde você pode ter até três planos por consulta (com base na seletividade, cada plano é sensível ao sniffing). Mas testei seu código com um nível de compatibilidade menor para meu banco de dados e ainda assim obtivemos planos diferentes.
Então, o próximo suspeito é recompilar para cada execução. Eu conectei abaixo do rastreamento:
E aí está. Um evento de recompilação, com recompile_cause sendo " Estatísticas alteradas ".
Ou seja, como você preencheu uma tabela com dados suficientes e depois fez um SELECT, o SQL Server atualizará as estatísticas para você, o que por sua vez está gerando uma recompilação.