Estou executando uma operação de exclusão em uma tabela muito grande do servidor sql com base na consulta, conforme discutido abaixo.
delete db.st_table_1
where service_date between(select min(service_date) from stg_table)
and (select max(service_date) from stg_table);
stg_table e stg_table_1 não possuem índices em service_date.
ambas as tabelas são carregadas com milhões de linhas de dados e a operação de exclusão está demorando muito. Solicitando sua sugestão para melhorar o desempenho desta consulta.
Eu me referi à estratégia descrita na pergunta abaixo, mas não consegui entender como implementá-la.
Como excluir grande quantidade de dados no servidor sql sem perda de dados?
solicitando sua gentil sugestão sobre isso.
Atualizar:
select * into db.temp_stg_table_1
from db.stg_table_1
where service_date not between( select min(service_date) from db.stg_table)
and (select max(service_date) from db.stg_table);
exec sp_rename 'stg_table_1' , 'stg_table_1_old'
exec sp_rename 'temp_stg_table_1' , 'test_table_1'
drop table stg_table_1_old
que tal se ir com a lógica acima para excluir os milhões de registros. quaisquer vantagens e desvantagens com isso.
Testando com base em seus comentários
Testado no SQL Server 2014 SP3
DDL
PK's + Índices agrupados em campos de identidade.
DML
2,5 milhões de linhas
dbo.st_table_1
e 5 milhões de linhas emdbo.stg_table
(quase) todas essas 2,5 milhões de linhas serão excluídas pela consulta, que é mais de 10 vezes menor que a sua.Executando sua consulta
O plano de execução real para sua instrução de exclusão básica
Como esperado,
dbo.stg_table
é acessado duas vezes para obter os valores máximo e mínimo com uma agregação de fluxo. O tempo de CPU e decorrido / tempo de execução:Uma dica de índice ausente é adicionada ao plano de execução:
No entanto , quando adicionamos o índice, uma classificação extra aparece para excluir as linhas desse índice recém-adicionado:
O plano
E o tempo de CPU / tempo decorrido aumenta:
YMMV , mas no meu exemplo, com base em seus comentários sobre os dados, não melhorou a consulta.
Criando um índice em
[dbo].[stg_table]
Como resultado, o
MAX()
andMIN()
pode aproveitar o índice recém-criado para retornar apenas uma linha em vez de uma verificação completa do índice clusterizado:Com o tempo de execução melhorado:
E o plano de execução
Mas isso é baseado apenas na indexação e no meu próprio exemplo. Prossiga por sua conta e risco.
Notas Extras
Você deve dividir essa exclusão em lotes separados para que ela não preencha o arquivo de log e não tenha um grande bloco de exclusão com falha / sucesso.
Você também pode considerar usar
(TABLOCK)
para que toda a tabela esteja bloqueada desde o início.Atualização:
SELECT INTO
+sp_rename
Além do desempenho,
sp_rename
precisa de umSch-M
bloqueio para ser concluído, o que significa que ele precisa esperar que todas as outras sessões liberem seus bloqueios na tabela antes de poder ser modificado. Quaisquer índices/restrições na tabela original desaparecerão e você terá que recriá-los.Quando executo a consulta em meus próprios dados:
Isso não representa seus dados, lembre-se disso.
Ele está lendo todas as linhas para retornar 0, o que não é o ideal.
Com um alto tempo de execução:
Mas isso não é realmente significativo sem mais informações sobre seus dados. Um plano de consulta seria necessário para fornecer conselhos mais corretos.
Eu simplesmente nunca excluiria 37 milhões de linhas em uma instrução . Não se trata do plano de execução que você obtém - a sobrecarga de encontrar linhas para excluir (se você tem sniffing de parâmetro afetando a localização dessas linhas ou não) é muito menor do que a sobrecarga de realmente excluí-las e registrar essas exclusões. Se você dividir isso em partes, poderá amortizar esse custo ao longo do tempo e processar as exclusões em uma programação que seja adequada à sua fantasia, em vez de tudo de uma vez.
Você também pode considerar a durabilidade atrasada se estiver em uma versão moderna o suficiente do SQL Server (consulte esta resposta e esta postagem de blog ).
A consulta acima pode funcionar bem devido ao índice ausente, mas a consulta ainda está errada.
Peguei o exemplo acima e executei sem Index, demorou 18 segundos para excluir 410792 linhas.
Se eu criar o Index como acima, sem dúvidas, ele terá o melhor desempenho.
Sub Query
emWhere
condições, pode darHigh Cardianility Estimate
em consulta complexa.Optimize query
do queindex
.Ambos são importantes.Observação :
Se o desempenho for ruim ou pior por causa
Parameter Sniffing
disso, você deve encontrar uma maneira adequada de evitarParameter sniffing
, caso contrário, você deve IGNORÁ-lo.Afinal nem tudo
Store Procedure
é escrito comOPTION RECOMPILE
.Pelo que entendi, no meu script
@FromDate
e@Todate
não são parâmetros proc, são variáveis locais, então não há dúvida deParameter Sniffing
.