Hoje descobri que o disco rígido que armazena meus bancos de dados estava cheio. Isso já aconteceu antes, geralmente a causa é bastante evidente. Normalmente, há uma consulta incorreta, que causa grandes vazamentos no tempdb, que crescem até o disco ficar cheio. Desta vez foi um pouco menos evidente o que aconteceu, já que tempdb não foi a causa da unidade cheia, foi o próprio banco de dados.
Os fatos:
- O tamanho normal do banco de dados é de cerca de 55 GB, cresceu para 605 GB.
- O arquivo de log tem tamanho normal, o arquivo de dados é enorme.
- Datafile tem 85% de espaço disponível (eu interpreto isso como 'ar': espaço que foi usado, mas foi liberado. O SQL Server reserva todo o espaço uma vez alocado).
- O tamanho do Tempdb é normal.
Encontrei a causa provável; há uma consulta que seleciona muitas linhas (junção ruim causa a seleção de 11 bilhões de linhas onde são esperadas algumas centenas de milhares). Esta é uma SELECT INTO
consulta, o que me fez pensar se o seguinte cenário poderia ter acontecido:
- SELECT INTO é executado
- A tabela de destino é criada
- Os dados são inseridos conforme são selecionados
- O disco enche, fazendo com que a inserção falhe
- SELECT INTO é abortado e revertido
- A reversão libera espaço (os dados já inseridos são removidos), mas o SQL Server não libera o espaço liberado.
Nesta situação, no entanto, eu não esperava que a tabela criada pelo SELECT INTO
ainda existisse, ela deveria ser descartada pelo rollback. Eu testei isso:
BEGIN TRANSACTION
SELECT T.x
INTO TMP.test
FROM (VALUES(1))T(x)
ROLLBACK
SELECT *
FROM TMP.test
Isto resulta em:
(1 row affected)
Msg 208, Level 16, State 1, Line 8
Invalid object name 'TMP.test'.
No entanto, a tabela de destino existe. A consulta real não foi executada em uma transação explícita, isso pode explicar a existência da tabela de destino?
As suposições que esbocei aqui estão corretas? Este é um cenário provável de ter acontecido?