Como posso remover um plano de execução incorreto do Banco de Dados SQL do Azure?

12

DBCC FREEPROCCACHEnão funciona no banco de dados SQL do Azure. De que outra forma eu posso forçar um plano a sair do cache de uma maneira que não prejudique o sistema de produção (ou seja, não posso simplesmente alterar as tabelas de maneira indesejada)? Isso é especificamente para SQL criado pelo Entity Framework, portanto, esses não são procs armazenados autogerenciados - é efetivamente um SQL dinâmico.

(A fonte apresentava índices ruins -> estatísticas ruins, etc. Isso tudo foi corrigido, mas um plano ruim não vai acabar.)

ATUALIZAÇÃO: Selecionei a solução de @ mrdenny quando ele chegou lá primeiro. No entanto, estou usando com êxito o script de @Aaron Bertrand para executar o trabalho. Obrigado a todos pela ajuda !!

Jaxidian
fonte
Você pode executar um sp_recompile no Azure?
mrdenny
Sim. Com que precisão eu o executaria? Não temos procs armazenados. Este é o SQL dinâmico executado sp_executesql.
precisa saber é o seguinte
2
Você pode executá-lo na mesa e isso deve liberar os planos que usam essa tabela. (Se isso funciona eu vou fazer isso uma resposta.)
mrdenny
1
Eu apenas tentei isso em uma tabela e, aparentemente, bloqueia a tabela em uma transação durante o processamento. Eu tentei em uma tabela de 10 colunas com apenas 24 registros e levou mais de um minuto para terminar. Durante esse período, não foi possível consultar a tabela. Não posso executar algo assim em nossas tabelas reais em Produção!
precisa saber é o seguinte
1
Porra, isso é uma chatice. Parece que você precisará fazer uma alteração no esquema, como adicionar uma coluna anulável e soltá-la. Isso limpará o cache também e deve ser rápido. O teste dirá com certeza.
precisa saber é o seguinte

Respostas:

12

O SQL do Azure agora suporta diretamente isso

O Banco de Dados SQL do Azure suporta diretamente a limpeza do cache de proc do banco de dados do usuário atual sem nenhum hacks:

ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;

informação adicional

O script a seguir (de Shannon Gowen ) pode ser usado para assistir o processo passo a passo:

-- run this script against a user database, not master
-- count number of plans currently in cache
select count(*) from sys.dm_exec_cached_plans;

-- Executing this statement will clear the procedure cache in the current database, which means that all queries will have to recompile.
ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;

-- count number of plans in cache now, after they were cleared from cache
select count(*) from sys.dm_exec_cached_plans;

-- list available plans
select * from sys.dm_exec_cached_plans;
Todd Menier
fonte
Ainda não tentei isso, mas se isso é realmente funcional, provavelmente esta é a "melhor" resposta a partir do início de 2017. Obrigado por isso - não fazia ideia de que isso estava lá! :-)
Jaxidian
Eu tentei isso (em um banco de dados Premium) e funcionou.
Remi Lemarchand
Eu sinalizei isso como uma "Resposta Aceita" atualizada, mas ainda não testei isso. Estou baseando isso diretamente no feedback de Todd e Remi. Obrigado a todos!
precisa saber é o seguinte
Só para revisitar, usei isso e funcionou bem para mim! Estou adicionando alguns scripts adicionais à resposta de Todd aqui para enriquecê-lo, mas o post dele acertou em cheio na cabeça.
precisa
Isso não parece funcionar para mim - apenas é executado, mas as listas ainda estão cheias - estou no SQL Azure - o que pode estar errado?
Dirk Boer
12

Atualmente, não há uma maneira explícita de fazer isso, mas esse não é um cenário permanente (o comando DBCC ainda não é suportado, mas leia no Query Store ). Mesmo quando a ocorrência de alteração de esquema é aceitável, pode não ser o que você deseja, porque invalidará todos os planos relacionados ao objeto subjacente, não apenas o ruim.

Não é necessário crédito para isso, mas é muito fácil criar SQL dinâmico para executar a mesma operação em várias tabelas:

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += N'ALTER TABLE '
  + QUOTENAME(SCHEMA_NAME([schema_id])) 
  + '.' + QUOTENAME(name) + ' ADD fake_column INT NULL;
  ALTER TABLE ' 
  + QUOTENAME(SCHEMA_NAME([schema_id]))
  + '.' + QUOTENAME(name) + ' DROP COLUMN fake_column;'
FROM sys.tables
--WHERE name IN, LIKE, etc.

PRINT @sql;

-- if the command > 8K, you can see the second chunk e.g.

PRINT SUBSTRING(@sql, 8001, 8000);

--EXEC sys.sp_executesql @sql;

(Eu escrevi uma dica sobre esse problema "comprimento do SQL dinâmico" ...)

Aaron Bertrand
fonte
No meu caso, removê-los todos é muito preferível a deixar os maus lá. Obrigado pela atenção. Sei que você não pode me dizer características, mas pode me dizer quando não pode mais ficar restrito a falar sobre coisas sobre as quais não pode falar? ;-)
Jaxidian
Isso também é classificado, desculpe. :-)
Aaron Bertrand
Não sei o que você quer dizer com link. O que eu quis dizer é que sua nvarchar(max)variável atinge um limite após 4000 caracteres, 8000 caracteres se eu mudar para varchar(max). Executando esse script exato. Temos ~ 450 mesas, por isso atingimos com facilidade (~ 30/60 mesas). varchar(max)é uma sintaxe válida, é idêntica varchar(8000)e nvarchar(max)é idêntica a nvarchar(4000).
precisa saber é o seguinte
3
Bem, sim, quando você PRINTcomanda, ele mostra apenas 8000 bytes. Essa é uma limitação do PRINTcomando, não do Azure. Se você executar o comando, ele funcionará mesmo que você não possa inspecionar visualmente a coisa toda.
Aaron Bertrand
desculpe, acho que você está certo! Obrigado por me corrigir! É o que acontece quando sua esposa esperava que você partisse há 25 minutos ... ;-) Esse script funciona perfeitamente para mim!
precisa saber é o seguinte
6

Adicione uma coluna anulável à tabela e solte a coluna. Isso forçará o SQL a liberar o cache para esse objeto.

Quanto a fazer todas as tabelas, um cursor deve fazer o truque. Basta usar um nome de coluna que nunca existirá em nenhuma tabela como 'zzzzzz_go_away' ou algo assim.

mrdenny
fonte
4

O Banco de Dados SQL do Azure atualmente não oferece suporte DBCC FREEPROCCACHE, portanto você não pode remover manualmente um plano de execução do cache. No entanto, se você fizer alterações em uma tabela ou exibição referenciada pela consulta ( ALTER TABLE/ ALTER VIEW), o plano será removido do cache. ( Referência .)

Kin Shah
fonte
Eu já sabia tudo o que você postou aqui. Este não é um procedimento armazenado nem uma exibição, portanto não posso modificar um deles. Como eu poderia modificar minhas tabelas de forma insignificante, enquanto estava sob carga e sem causar nenhum tempo de inatividade ou bloqueio da tabela, para acionar isso?
precisa saber é o seguinte
1
Você pode adicionar uma coluna fictícia e soltá-la. Isso removerá o plano do cache. Qual é o tamanho da mesa?
Kin Shah
Essa acabou sendo a solução, conforme recomendado por @mrdenny. Obrigado pela ajuda!! :-)
Jaxidian
1
Graças ... Apenas alguns segundos curta no tempo .. estava respondendo algum outro post sobre Stackexchange ...
Kin Shah
1

Para limpar todo o plano de execução, use o seguinte:

    SET NOCOUNT ON

DECLARE @lcl_name VARCHAR(100)
DECLARE @addcolumnSql nVARCHAR(MAX)
DECLARE @dropcolumnSql nVARCHAR(MAX)

DECLARE cur_name CURSOR FOR
SELECT name
FROM sysobjects
WHERE type = 'U'
OPEN cur_name
FETCH NEXT FROM cur_name INTO @lcl_name
WHILE @@Fetch_status = 0
BEGIN
set @addcolumnSql = 'alter table [' + @lcl_name + '] add temp_col_to_clear_exec_plan bit'
EXEcute sp_executesql @addcolumnSql
print @addcolumnSql
set @dropcolumnSql = 'alter table [' + @lcl_name + '] drop column temp_col_to_clear_exec_plan'
EXEcute sp_executesql @dropcolumnSql
print @dropcolumnSql
--  EXEC (@lcl_name )
FETCH NEXT FROM cur_name INTO @lcl_name
END
CLOSE cur_name
DEALLOCATE cur_name
SET NOCOUNT OFF

Se você alterar uma tabela ou exibir uma referência a ela, o plano de execução será limpo.

Um pouco mais explicado aqui http://christianarg.wordpress.com/2013/08/22/remove-execution-plans-from-the-procedure-cache-in-sql-azure/

cristão
fonte