Сегодня я обнаружил, что жесткий диск, на котором хранятся мои базы данных, переполнен. Это случалось раньше, обычно причина очевидна. Обычно это неверный запрос, который приводит к огромным разливам в базу данных tempdb, которая увеличивается до заполнения диска. На этот раз было немного менее очевидно, что произошло, так как tempdb не был причиной полного диска, это была сама база данных.
Факты:
- Обычный размер базы данных составляет около 55 ГБ, он вырос до 605 ГБ.
- Файл журнала имеет нормальный размер, файл данных огромен.
- Файл данных имеет 85% доступного пространства (я интерпретирую это как «воздух»: пространство, которое использовалось, но было освобождено. SQL Server резервирует все пространство после выделения).
- Размер Tempdb нормальный.
Я нашел вероятную причину; есть один запрос, который выбирает слишком много строк (плохое соединение приводит к выделению 11 миллиардов строк, где ожидается пара сотен тысяч). Это SELECT INTO
вопрос, который заставил меня задуматься, мог ли случиться следующий сценарий:
- SELECT INTO выполнен
- Целевая таблица создана
- Данные вставляются как они выбраны
- Диск заполняется, вызывая сбой вставки
- SELECT INTO отменяется и откатывается
- Откат освобождает пространство (уже вставленные данные удаляются), но SQL Server не освобождает освободившееся пространство.
В этой ситуации, однако, я бы не ожидал, что таблица, созданная с помощью, SELECT INTO
все еще существует, ее следует отбросить при откате. Я проверил это:
BEGIN TRANSACTION
SELECT T.x
INTO TMP.test
FROM (VALUES(1))T(x)
ROLLBACK
SELECT *
FROM TMP.test
Это приводит к:
(1 row affected)
Msg 208, Level 16, State 1, Line 8
Invalid object name 'TMP.test'.
Тем не менее целевая таблица существует. Фактический запрос не был выполнен в явной транзакции, может ли это объяснить существование целевой таблицы?
Являются ли предположения, которые я сделал здесь, правильными? Это вероятный сценарий произошел?