A “tabela vazia” do SQL Server fica lenta depois de excluir todos os (12 milhões) registros?

27

Eu tenho uma instância do SQL Server 2008 com aproximadamente 150 colunas. Eu preenchi anteriormente esta tabela com aproximadamente 12 milhões de entradas, mas desde então a limpou em preparação para um novo conjunto de dados.

No entanto, os comandos que uma vez correu imediatamente em uma mesa vazia, como count(*)e select top 1000em SQL Management Studiotomar agora eras para ser executado.

SELECT COUNT(*) FROM TABLE_NAME 

demorou 11 minutos para retornar 0 e SELECT TOP 1000levou quase 10 minutos para retornar uma mesa vazia.

Também notei que o espaço livre no disco rígido desapareceu literalmente (de cerca de 100G a 20G). A única coisa que aconteceu foi uma única consulta que executei:

DELETE FROM TABLE_NAME

O que anda acontecendo no mundo?!?


fonte
5
Qual modelo de recuperação seu banco de dados usa? Se estiver "Cheio", sua instância SQL armazenará um registro de todas essas exclusões, que podem ser para onde foi o seu espaço livre. Se a recuperação total for um requisito, recomendo usar em TRUNCATE TABLEvez de DELETE FROM.
Tullo_x86
2
150 colunas? Essa tabela pode estar cheia demais - a maioria das tuplas deve ser bem menor. Impossível dizer sem contexto completo, no entanto.
Clockwork-Muse

Respostas:

42

Você já foi informado sobre por TRUNCATEque seria muito mais rápido / melhor / mais sexy do que DELETE, mas ainda há uma pergunta a ser resolvida:

Por que é SELECTmais lento após a DELETE conclusão ?

Isso ocorre porque DELETEapenas as linhas são fantasmas . A tabela é tão grande quanto quando tinha 12M linhas, mesmo que não tenha nenhuma. Para contar as linhas (0), leva o tempo necessário para contar 12M linhas. Com o tempo, o processo de limpeza de fantasmas coletará esses registros fantasma e desalocará as páginas que continham apenas fantasmas, e seus SELECTs irão acelerar. Mas agora, se você fizer o check- Skipped Ghosted Records/secin, o perfmon provavelmente disparará durante SELECT COUNT(*). Você também pode acelerar as coisas pela reconstrução da tabela: ALTER TABLE ... REBUILD.

TRUNCATE também teria resolvido esse problema, já que não deixa fantasmas para trás.

Consulte também Dentro do mecanismo de armazenamento: limpeza do Ghost em profundidade .

Remus Rusanu
fonte
13

DELETEAs instruções excluem linhas de uma tabela uma de cada vez, registrando cada linha na transaction log, bem como mantendo as log sequence number (LSN)informações. Como você mencionou que sua tabela possui dados enormes (12 milhões de registros), após a exclusão do disco rígido sem espaço, verifique o tamanho do arquivo de log do banco de dados. Provavelmente teria crescido.

uma maneira melhor teria sido:

TRUNCATE TABLE_NAME

fonte
2
+1, exatamente o mesmo para o banco de dados Oracle. Se você usar instruções que causam o registro de registros, o banco de dados ficará lento com o tempo.
Petro Semeniuk
@PetroSemeniuk Pelo que me lembro no Oracle, excluir deixa a marca d'água alta sozinha, truncar redefinirá a marca d'água alta. Acredito que qualquer operação que exija uma verificação completa varrerá os blocos até a marca d'água alta. Portanto, a exclusão pode ajudar nas operações indexadas, mas não nas varreduras. TRUNCATE foi a operação correta.
Glenn
3

(Originalmente, isso foi um comentário à resposta de @ DaveE, mas eu coloquei em sua própria resposta porque demorou muito)

TRUNCATE é uma operação registrada. Tem que ser de outra forma, não é compatível com ACID. No entanto, diferenças entre TRUNCATEe DELETE:

  • Uso do espaço de log: TRUNCATEregistra apenas páginas / extensões * liberadas, enquanto DELETEregistra linhas individuais.
  • Uso de bloqueio: TRUNCATEgeralmente usa menos bloqueios, já que são necessários bloqueios de tabela e bloqueios de página, ao contrário dos DELETEbloqueios de linha **.
  • IDENTITYsequências: TRUNCATEredefine a sequência de identidade em uma tabela, se presente.

(* Uma extensão = 8 páginas. TRUNCATERegistrará / removerá extensões se todas pertencerem a essa tabela; caso contrário, registrará / removerá páginas de extensões misturadas.

** Um efeito colateral disso é que DELETE FROM TABLEpode deixar páginas vazias alocadas para a tabela, dependendo se a operação pode ou não obter um bloqueio exclusivo da tabela.)

Então (voltando à pergunta original), TRUNCATE TABLEé conclusivamente melhor do que DELETE FROM TABLEse você estiver esvaziando a tabela, mas quiser manter a estrutura (NB: TRUNCATEnão pode ser usado em uma tabela referenciada por uma chave estrangeira de outra tabela).

Conforme observado no comentário de @ Tullo, verifique também o modelo de recuperação do seu banco de dados - se estiver cheio, você precisará começar a fazer backups de log ou alterar seu modelo de recuperação para simples. Depois de fazer uma dessas opções, você provavelmente reduzirá seu arquivo de log como uma operação única (NB: somente arquivo de log ) para recuperar todo esse espaço livre.

Finalmente, outra coisa a ter em atenção - as estatísticas da tabela. execute UPDATE STATISTICS <TABLENAME>' afterTRUNCATE /DELETE` para que o otimizador de consultas não seja acionado por estatísticas antigas.

Simon Righarts
fonte
2

(NOTA: eu não sou um DBA) DELETE é uma operação registrada e não libera o espaço usado. Você provavelmente tem um grande log de transações ocupando varreduras de espaço e tabela em execução no espaço de tabela 'vazio'. Eu acho que você precisa limpar o log de transações e reduzir seu banco de dados. Este artigo StackOverflow deve começar.

E use TRUNCATE TABLE quando desejar fazer isso no futuro.

Edição: Minha declaração sobre TRUNCATE não está sendo registrado estava com erro. removido.

DaveE
fonte