Утро, звонок, у людей на экране красная простыня:
The transaction log for database 'tempdb' is full due to 'ACTIVE_TRANSACTION' ... native=9002
Проведение не идёт, документы не записываются, в чате уже спрашивают, когда заработает. Админ на обеде, доступа к SQL Server у вас нет и не будет. Дальше обычно начинается гадание: перезапустить сервер приложений, попросить кого-нибудь сделать SHRINK, посмотреть, не кончилось ли место на диске.
Гадать не нужно. На все три вопроса, которые тут важны, отвечает сама платформа, и отвечает из 1С, без единого запроса к СУБД.
Что вообще означает эта ошибка
Читается она по частям, и каждая часть важна.
The transaction log ... is full - заполнился журнал транзакций, а не файл данных и не диск. Это разные вещи, и лечатся они по-разному.
due to 'ACTIVE_TRANSACTION' - вот причина. Журнал заполнился не потому, что он маленький, а потому что его нельзя очистить: какая-то транзакция ещё активна, и SQL Server не имеет права затирать записи, которые могут ей понадобиться для отката.
native=9002 - код ошибки, по которому это ищут в поиске.
Перевод на человеческий: кто-то открыл транзакцию и долго её не закрывает. Диск тут следствие, а не причина. Добавите места - журнал вырастет дальше и упрётся снова, только позже и на большем объёме.
Причина очистки видна в одном показателе - log_reuse_wait_desc. Значений там немного, и каждое означает свой сценарий:
| Значение | Что происходит |
|---|---|
ACTIVE_TRANSACTION |
живая транзакция держит журнал. Тот самый случай из 9002 |
LOG_BACKUP |
база в полной модели восстановления, а бэкапов журнала нет. Журнал будет расти, пока не кончится диск |
CHECKPOINT |
контрольная точка не прошла, обычно временно |
REPLICATION или AVAILABILITY_REPLICA |
журнал ждёт подписчика или реплику |
NOTHING |
ничего не мешает, журнал переиспользуется нормально |
Разница принципиальная. LOG_BACKUP - это не авария, а неверная настройка: полная модель восстановления без регулярных бэкапов журнала. Такая база растёт молча и годами, а падает в тот день, когда на диске кончилось место. ACTIVE_TRANSACTION - это авария прямо сейчас, и у неё есть виновник с именем.
Почему это чаще всего бьёт именно по tempdb
В 9002 у пользователей 1С почти всегда фигурирует tempdb, и это не совпадение.
Во-первых, каждое ПОМЕСТИТЬ в пакетном запросе - это реальная таблица в tempdb. Сортировки и соединения, которым не хватило памяти, тоже уезжают туда.
Во-вторых, и это главное: в режиме управляемых блокировок платформа включает READ COMMITTED SNAPSHOT. Версии изменяемых строк копятся в tempdb и не чистятся, пока жива хоть одна старая транзакция. Одна забытая транзакция на четверть суток - и хранилище версий растёт всё это время, а вместе с ним журнал tempdb.
Отсюда неприятное следствие: авария в tempdb может быть вызвана транзакцией в совсем другой базе на том же сервере. Искать виновника внутри базы, где сработала ошибка, бесполезно.
Как найти держателя, не имея доступа к СУБД
Это самая полезная часть, и она мало кому известна.
Идентификатор транзакции в журнале регистрации 1С выглядит так:
21.08.2026 8:41:07 (2166970)
Момент старта транзакции записан прямо в идентификаторе. Конец берётся по последней записи этой же транзакции. Отсюда получается длительность, а вместе с ней - пользователь, компьютер, приложение и список объектов, которые транзакция трогала.
Работает это даже тогда, когда события "Транзакция. Начало" и "Транзакция. Завершение" в настройках журнала выключены: поле Транзакция заполняется у любой записи, сделанной внутри транзакции. То есть транзакция видна по своим следам, даже если о её старте никто не писал.
На реальном журнале из 46 616 записей группировка по этому полю дала 12 252 транзакции, и самые длинные всплыли сразу: 1 630 минут и 1 331 минута. Это не "долго", это сутки с лишним. Обе принадлежали фоновым сеансам одного приложения, и обе были живы в момент разбора.
Дальше вопрос закрывается: у транзакции есть имя пользователя, компьютер и приложение. Идёте в консоль кластера 1С, находите сеанс, завершаете его штатно.
Штатно, а не KILL
Соблазн большой: админ видит SPID, делает KILL, журнал освобождается. Так делать не надо, и вот почему.
KILL на стороне СУБД откатывает транзакцию, но сеанс 1С об этом не знает. Он остаётся в подвешенном состоянии, и дальше поведение зависит от того, что этот сеанс делал: от безобидного "пользователь получил ошибку и переоткрыл документ" до заблокированных объектов, которые придётся снимать руками.
Правильный порядок такой:
- по имени пользователя и компьютеру находите сеанс в консоли кластера 1С;
- смотрите, что это: клиент, фоновое задание, регламентное задание;
- завершаете сеанс средствами 1С;
- и только если сеанс уже не отвечает - разговариваете с админом про
KILL.
Откат при этом всё равно займёт время, сопоставимое с временем работы транзакции. Транзакция, которая писала сутки, будет откатываться не мгновенно, и это нормально. Хуже другое: пока идёт откат, журнал не освобождается, и люди продолжают получать 9002. Поэтому "убить и забыть" не работает, надо дождаться.
Что действительно уменьшит файл журнала
Тут два разных вопроса, которые постоянно путают.
Освободить место внутри журнала - это про причину. Если LOG_BACKUP - сделать бэкап журнала (и завести регламент, иначе повторится). Если ACTIVE_TRANSACTION - закрыть транзакцию. Пока причина жива, ничего не поможет.
Уменьшить сам файл на диске - это SHRINK, и он лечит только последствие. Причём лечит плохо: журнал, ужатый в ноль, тут же начинает расти обратно автоприростом, а рост журнала - это блокирующая операция, она останавливает запись, пока не выделит место. Кусками по 64 МБ на журнале в несколько десятков гигабайт - это сотни и тысячи таких остановок.
Практический вывод: SHRINK уместен один раз, после разовой аварии, чтобы вернуть диск. Как регулярная мера - вредная привычка. Постоянное решение это либо бэкапы журнала, либо разумный потолок размера, чтобы база упиралась в понятную ошибку, а не съедала общий диск.
Отдельный сюжет: безлимитный журнал
В настройках файла журнала часто стоит "без ограничения". Выглядит удобно, работает как мина.
Журнал на общем диске без потолка однажды съедает всё свободное место, и падает при этом не только 1С, а всё, что живёт на этом диске. Разница между "журнал упёрся в свой лимит" и "на диске кончилось место" - только в том, где чинить. В первом случае у вас понятная ошибка и работающий сервер, во втором - тихая катастрофа с непредсказуемым списком пострадавших.
Та же болезнь у PostgreSQL
У PostgreSQL журнала транзакций в терминологии MS SQL нет, но механика та же: растёт каталог pg_wal, и причины ровно те четыре, что и у ACTIVE_TRANSACTION с LOG_BACKUP, только называются иначе.
Реплика или слот логической репликации, который никто не читает, держит WAL столько, сколько нужно этому слоту, а не столько, сколько нужно базе. Сервер честно копит файлы под подписчика, который отвалился неделю назад и о себе не напоминает.
archive_command, который начал падать - диск архива кончился, сеть до хранилища легла, права протухли - вторая причина: WAL не удаляется, пока не архивирован, а архивация не идёт, значит он копится бесконечно.
Третья и четвёртая причины зеркалят ACTIVE_TRANSACTION. Долгая транзакция держит горизонт xmin, и сервер не может почистить WAL и старые версии строк, пока она жива. Подвисшая prepared-транзакция (двухфазный commit, который начали и не завершили) держит горизонт так же цепко, только в обычном списке активных запросов её не видно - это отдельная сущность в системном каталоге, а не сессия.
Разбор в обработке идёт тем же принципом, что и для MS SQL: не голые числа, а вердикт по каждой причине - чинить, внимание, норма - и что чинить в первую очередь.
Профилактика та же идея, что и с безлимитным журналом MS SQL: не ждать аварии, а смотреть заранее. pg_replication_slots показывает, какой слот неактивен и сколько WAL под него скопилось. Слот сам не удаляется никогда, даже если подписчик отвалился месяц назад - его снимают руками, и это единственная строка, которая часто решает всю проблему без единой минуты простоя.
Как это выглядит собранным вместе
Мы сложили всё перечисленное в обработку: Журнал транзакций переполнен: кто держит и что делать.
Она снимает со стороны 1С то, что доступно платформе: самые длинные транзакции с пользователем, компьютером и объектами, ошибки СУБД из журнала регистрации, фоновые и регламентные задания, сеансы, режим блокировок базы. Это одна кнопка и минута времени, доступ к серверу баз данных не нужен.
Для стороны СУБД она печатает готовый скрипт администратору. Не "посмотри там что-нибудь", а конкретный текст, который человек выполняет в SSMS или psql и возвращает результат обратно в обработку. Результат читать глазами не надо: он заканчивается блоком "Итог", а обработка разбирает его в вердикты - чинить, внимание, норма - и сортирует так, что сначала идёт то, что чинить. У каждой строки написано, что это значит и чем грозит.
Скриптов восемь: пять для MS SQL и три для PostgreSQL, потому что у PostgreSQL та же болезнь называется иначе - раздувшийся pg_wal, слоты репликации, зависшие prepared-транзакции, долгий xmin.
К СУБД обработка не подключается принципиально и ничего не меняет: ни в базе, ни в настройках сервера. Скрипт, который уменьшает файл журнала, команды печатает, а не выполняет - решение остаётся за человеком.
Что забрать из статьи, даже если обработка не нужна
- 9002 - это не "мало места", это "журнал нельзя очистить". Первый вопрос всегда
log_reuse_wait_desc, а не размер диска. LOG_BACKUPиACTIVE_TRANSACTION- разные болезни. Первая лечится регламентом бэкапов, вторая поиском виновника.- Держателя видно из 1С. Момент старта транзакции лежит прямо в её идентификаторе в журнале регистрации, и по нему считается длительность без всякого доступа к СУБД.
- Завершать - средствами 1С,
KILLтолько как крайняя мера, и всё равно ждать отката. SHRINK- не лечение, а разовая уборка после аварии.- Безлимитный журнал на общем диске превращает локальную проблему в общую.
Вступайте в нашу телеграмм-группу Инфостарт