Сьогодні я виявив жорсткий диск, у якому зберігаються мої бази даних. Це траплялося і раніше, зазвичай причина досить очевидна. Зазвичай є поганий запит, який спричиняє величезні розливи до 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'.
І все ж цільова таблиця існує. Фактичний запит не виконувався в явній транзакції, чи може це пояснити існування цільової таблиці?
Чи правильні припущення, які я накреслив тут, правильні? Це ймовірний сценарій трапився?