Посреди рабочего дня у пользователей 1С выпадает окно «Ошибка СУБД», работа встаёт, а в тексте — что-то про tempdb и транзакции. Разберём, что именно сломалось, как потушить пожар за пять минут и что сделать, чтобы он не повторялся. Без паники и без «перезагрузите сервер».
Симптом
Ошибка СУБД: Microsoft SQL Server Native Client 11.0: The transaction log for database 'tempdb' is full due to 'ACTIVE_TRANSACTION' and the holdup lsn is (61800:856:252). HRESULT=80040E14, SQLSrvr: SQLSTATE=42000, state=4, Severity=11, native=9002, line=1
Выглядит страшно, но в сообщении уже есть весь диагноз, если читать его по частям:
- The transaction log for database 'tempdb' is full — заполнился журнал транзакций служебной базы tempdb. Не данные, не диск с вашей рабочей базой — именно журнал tempdb.
- due to 'ACTIVE_TRANSACTION' — журнал не может очиститься, потому что какая-то транзакция всё ещё активна и держит его хвост. SQL Server не имеет права затереть журнальные записи, пока транзакция, которой они могут понадобиться для отката, не завершилась.
- holdup lsn — номер журнальной записи (Log Sequence Number), в которую упёрлась очистка. По сути — координаты «виновника».
- native=9002 — код ошибки SQL Server «журнал переполнен». Запомните его: по нему проще всего искать и мониторить.
Перевод на человеческий: кто-то открыл транзакцию, долго её не закрывает, и всё это время журнал tempdb растёт. Дорос до предела — и все, кому нужна tempdb (то есть практически все), получили ошибку.
Почему это касается каждой базы 1С
tempdb — общая рабочая площадка SQL Server, и 1С пользуется ею гораздо интенсивнее, чем кажется:
- Временные таблицы запросов. Каждый ПОМЕСТИТЬ в пакетном запросе — это таблица в tempdb. Тяжёлый отчёт на 15 пакетов может создать десяток таблиц и держать их до конца выполнения.
- Сортировки и соединения. Когда серверу не хватает памяти на ORDER BY или JOIN, он сбрасывает промежуточные данные в tempdb.
- Версии строк. Это главный неочевидный пункт. В режиме управляемых блокировок (стандарт для современных конфигураций) 1С включает на базе READ COMMITTED SNAPSHOT — и SQL Server начинает хранить версии изменяемых строк в tempdb, в version store. Пока жива хоть одна длинная транзакция, version store не очищается и растёт.
- Реструктуризация и обновления. Обновление конфигурации на большой таблице — это тоже гигабайты во временном пространстве.
Поэтому «переполнился журнал tempdb» почти всегда означает не «диск маленький», а «в системе есть длинная транзакция, которую что-то породило». Диск — следствие.
Первая помощь: пять минут на диагноз
Всё ниже — скрипты диагностики для администратора СУБД, они только читают служебную информацию.
Шаг 1. Убедиться, что дело в журнале, и посмотреть его заполненность:
DBCC SQLPERF(LOGSPACE);
В строке tempdb будет процент занятости журнала. 90+ — вы по адресу.
Шаг 2. Спросить у tempdb, что мешает очистке журнала:
SELECT name, log_reuse_wait_desc FROM sys.databases WHERE name = 'tempdb';
Если видите ACTIVE_TRANSACTION — подтверждение диагноза из окна ошибки.
Шаг 3. Найти самую старую активную транзакцию:
DBCC OPENTRAN('tempdb');
Получите SPID сессии и время старта транзакции. Часто время старта говорит само за себя: транзакция живёт 40 минут — а «нормальные» транзакции 1С живут секунды.
Шаг 4. Понять, кто это:
SELECT s.session_id, s.host_name, s.program_name, s.login_name,
t.transaction_id, at.transaction_begin_time,
r.status, r.command, r.wait_type, r.total_elapsed_time / 1000 AS sec
FROM sys.dm_tran_session_transactions t
JOIN sys.dm_tran_active_transactions at ON at.transaction_id = t.transaction_id
JOIN sys.dm_exec_sessions s ON s.session_id = t.session_id
LEFT JOIN sys.dm_exec_requests r ON r.session_id = s.session_id
ORDER BY at.transaction_begin_time;
В верхних строках — самые старые транзакции. По host_name и program_name видно, это сеанс 1С, фоновое задание или чей-то Management Studio. Сопоставить SPID с конкретным сеансом 1С можно через консоль кластера: у сеанса отображается «Соединение с СУБД» — тот самый номер.
Шаг 5. Решение по ситуации. Вариантов три, в порядке предпочтения:
- Дождаться завершения, если процесс легитимный и близок к финалу (например, закрытие месяца на последней стадии). Иногда правильное действие — ничего не трогать 10 минут.
- Штатно завершить сеанс 1С — через консоль кластера. Транзакция откатится, журнал освободится.
- Крайняя мера для администратора — завершить сессию на стороне SQL Server. Помните: откат длинной транзакции может занять сравнимое с её жизнью время, и на время отката журнал всё ещё нужен.
Если журнал упёрся в потолок физически (стоит ограничение размера или кончился диск) — временно расширьте файл журнала или ограничение, чтобы система ожила, и только потом разбирайтесь с виновником. Расширять на пару гигабайт, а не «до бесконечности»: безлимитный журнал на общем диске однажды съест его весь.
Кто обычно оказывается виновником (наша статистика разборов)
По опыту расследований на базах от десятков гигабайт до нескольких терабайт, виновники распределяются примерно так:
- Самописная обработка с транзакцией на весь объём. «Обработать 500 000 строк в одной транзакции, чтобы было атомарно». Атомарно — будет; работать — не будет. Разбивайте на порции: тысяча документов — тысяча коротких транзакций.
- Тяжёлый отчёт в рабочее время. Пакетный запрос с десятком временных таблиц, каждая на миллионы строк. Сам по себе он не держит транзакцию часами, но параллельно с очередью проведения устраивает в tempdb тесноту, и первым падает самый невезучий.
- Фоновое задание, которое «зависло» в ожидании блокировки. Транзакция открыта, задание ждёт ресурс, журнал копится. Здесь лечится не журнал, а причина ожидания.
- Регламентные операции СУБД в неудачное окно — перестроение индексов поверх рабочего дня.
Профилактика: чтобы не повторялось
1. Настройте tempdb как боевую базу, а не как «само заведётся»
- Отдельный быстрый диск под tempdb — данные и журнал.
- Несколько файлов данных (стартово — по числу ядер, но не больше 8) одинакового размера.
- Начальный размер файлов — по реальному профилю нагрузки, а не 8 МБ по умолчанию. Если после каждой перезагрузки tempdb «разгоняется» автоприростами заново — задайте стартовый размер равным типичному рабочему.
- Автоприрост фиксированным шагом (например, 512 МБ), не процентами.
2. Уберите длинные транзакции в коде 1С
- Порционная обработка вместо «всё в одной транзакции». Правило простое: транзакция должна жить секунды.
- Не выполняйте в транзакции то, что может ждать: запросы к внешним сервисам, интерактивные вопросы пользователю, обращения к файлам.
- Проверьте фоновые задания: любое из них, открыв транзакцию и встав в очередь за блокировкой, превращается в того самого держателя журнала.
3. Наведите порядок во временных таблицах пакетных запросов
Каждая временная таблица, созданная через ПОМЕСТИТЬ и не уничтоженная до конца пакета, живёт в tempdb всё время выполнения запроса. В длинных отчётных пакетах это гигабайты, которые держатся зря: таблица нужна была в третьем пакете, а место занимает до пятнадцатого. Лечится дисциплиной УНИЧТОЖИТЬ: ставить его сразу после последнего использования таблицы. Вручную это муторно — для авторасстановки мы выложили обработку «Авто-УНИЧТОЖИТЬ: оптимизатор временных таблиц в пакетных запросах»: она разбирает пакет, находит место последнего использования каждой таблицы и расставляет УНИЧТОЖИТЬ сама.
4. Поставьте мониторинг, чтобы узнавать первым, а не от пользователей
- Алерт на заполнение журнала tempdb (порог 70–80%).
- Алерт на транзакции старше 5 минут — тот же запрос из шага 4, только по расписанию.
- Ошибка 9002 в журнале SQL Server — повод для уведомления, даже если «само рассосалось»: в следующий раз может не рассосаться.
Чек-лист на стену
- Ошибка 9002 по tempdb = где-то длинная транзакция. Диск — следствие.
- DBCC SQLPERF(LOGSPACE) U94; log_reuse_wait_desc U94; DBCC OPENTRAN — три команды, пять минут, виновник найден.
- Завершать — штатно через консоль кластера; kill — крайняя мера; откат тоже занимает время.
- Профилактика: настроенная tempdb, короткие транзакции, УНИЧТОЖИТЬ по месту, мониторинг.
Если у вас эта ошибка выскакивает регулярно и виновник каждый раз новый — это уже не случайность, а характер нагрузки: пора смотреть на систему целиком, от настроек СУБД до архитектуры самых тяжёлых обработок. Расскажите в комментариях, кто оказался держателем журнала у вас — соберём коллекцию типовых виновников.
Вступайте в нашу телеграмм-группу Инфостарт