При обслуживании крупных и давно эксплуатируемых баз данных на платформе 1С:Предприятие 7.7 администраторы и разработчики часто сталкиваются с проблемой долгого восстановления границы последовательности (ГП). Стандартный механизм восстановления последовательности работает в монопольном режиме и "до победного конца". Если база большая, а пользователи залезли "задним числом" на год или два назад, процесс проведения документов может затянуться на десятки часов.
Главная сложность заключается в том, что прервать стандартное восстановление безболезненно нельзя: Точка Актуальности (ТА) останется смещенной назад, итоги "поплывут", и базу нельзя будет открыть для полноценной работы пользователей в начале рабочего дня. В этой статье мы подробно рассмотрим, как программно контролировать процесс восстановления последовательности, останавливать его в заданное время без ущерба для итогов и существенно ускорять проведение документов.
Прежде чем переходить к алгоритмам остановки, давайте разберем физику процесса в 1С 7.7. В платформе существуют два важнейших понятия:
Когда мы запускаем штатное восстановление последовательности, платформа временно сдвигает ТА назад, на позицию восстанавливаемого документа, и начинает последовательно проводить документы один за другим, постепенно двигая ТА вперед. Если мы грубо прервем этот процесс (например, снимем задачу в диспетчере задач), ТА останется глубоко в прошлом. При попытке пользователей работать в такой базе начнется хаос: выписка документов сегодняшним днем будет вызывать пересчет итогов "на лету" за весь пропущенный период, что намертво заблокирует базу данных.
Самый надежный способ контролировать время проведения — отказаться от штатного монопольного восстановления последовательности и написать собственную обработку. Мы можем выбирать документы, входящие в последовательность, и проводить их поочередно. Перед проведением каждого документа мы будем проверять текущее системное время компьютера. Если лимит времени исчерпан (например, наступило 07:30 утра), обработка прекратит работу, корректно перенесет ТА на последний успешно проведенный документ и завершит работу системы.
Проанализируем пример кода для такой обработки. Для этого мы используем объект Последовательность и метод УстановитьТаНаДокумент().
Процедура ВосстановитьПоследовательностьСКонтролемВремени()
// Определяем время, когда необходимо гарантированно завершить работу
ВремяОстанова = "07:30:00";
// Получаем последовательность по ее идентификатору (например, Основная)
Послед = Последовательности.Получить("Основная");
// Определяем документ границы последовательности
ДокГраницы = Послед.ПолучитьГраницу();
Если ПустоеЗначение(ДокГраницы) = 1 Тогда
Предупреждение("Последовательность уже восстановлена!");
Возврат;
КонецЕсли;
// Запоминаем исходную ТА, чтобы знать, куда нам нужно вернуться в идеале
ИсходнаяТА = ПолучитьТА();
// Создаем выборку документов, начиная с границы последовательности
ВыборкаДоков = СоздатьОбъект("Документ");
ВыборкаДоков.ВыбратьДокументы(ПолучитьДатуДокумента(ДокГраницы), РабочаяДата());
Пока ВыборкаДоков.ПолучитьДокумент() = 1 Цикл
// Проверяем, входит ли документ в нашу последовательность
Если Послед.Принадлежит(ВыборкаДоков.ТекущийДокумент()) = 0 Тогда
Продолжить;
КонецЕсли;
// Проверяем лимит времени перед проведением очередного документа
Если ТекущееВремя() >= ВремяОстанова Тогда
Сообщить("Достигнут лимит времени! Процесс останавливается.");
Прервать;
КонецЕсли;
// Чтобы избежать нарушения итогов, перед проведением документа сдвигаем ТА
// Параметр -1 означает установку ТА непосредственно ПЕРЕД документом
УстановитьТаНаДокумент(ВыборкаДоков.ТекущийДокумент(), -1);
// Проводим документ
Попытка
ВыборкаДоков.Провести();
Сообщить("Успешно проведен документ: " + ВыборкаДоков.ТекущийДокумент());
Исключение
Сообщить("Ошибка проведения документа: " + ВыборкаДоков.ТекущийДокумент() + ". Восстановление прервано.");
Прервать;
КонецПопытки;
КонецЦикла;
// Корректно возвращаем ТА на место последнего проведенного документа
// или на исходную ТА, если проведение завершилось полностью.
// Это предотвратит "зависание" итогов в прошлом.
Если ВыборкаДоков.Выбран() = 1 Тогда
УстановитьТаНаДокумент(ВыборкаДоков.ТекущийДокумент(), 1);
Иначе
УстановитьТаНаДокумент(ИсходнаяТА, 1);
EndIf;
КонецПроцедуры
Рассмотрим подробнее логику этого кода. Метод УстановитьТаНаДокумент(Документ, -1) сдвигает точку актуальности непосредственно перед проведением документа. После успешного проведения мы можем сдвинуть ТА на этот документ с параметром 1 (что означает "после документа"). Таким образом, в любой момент остановки наши итоги всегда будут рассчитаны строго на актуальный момент времени, и база останется в работоспособном состоянии.
Часто в последовательность включено слишком много типов документов, проведение которых не влияет на конечную себестоимость или взаиморасчеты (например, ЗаявкаПокупателя, СчетНаОплату и т.д.). Проведение таких документов отнимает драгоценное процессорное время.
Выясним причину замедления и применим "умный" пропуск:
РасходнаяНакладная, ПоступлениеТоваров).УстановитьТаНаДокумент(Документ, 1) без физического вызова метода Провести().Выясним еще одну важную техническую причину, по которой 1С 7.7 медленно проводит документы. При проведении документов и обращении к регистрам (так называемые "черные запросы") платформа 1С 7.7 очень активно работает со своим каталогом временных файлов (обычно это системный каталог Temp пользователя). Платформа постоянно создает, пишет и читает временные файлы с флагом отключения кэширования операционной системы.
Чтобы ускорить этот процесс в несколько раз, выполним следующие шаги:
TEMP и TMP в сеансе, где запускается восстановление последовательности, на этот созданный RAM-диск.Если база данных работает в режиме 24/7 и монопольного времени ночью критически не хватает, рассмотрим архитектурный обходной путь с использованием распределенных баз данных или копий:
Важное замечание: При переносе таблиц напрямую из копии в рабочую базу необходимо строго следить за тем, чтобы в рабочей базе за это время пользователи не изменяли документы задним числом в восстанавливаемом периоде.
Если монопольно запустить базу нет никакой возможности, можно организовать проведение документов в разделенном (сетевом) режиме в фоновом режиме даже в рабочее время. Чтобы наша обработка не вешала базу и не вызывала постоянных ошибок блокировки таблиц (знаменитое Ожидание блокировки базы данных...), перед проведением каждого документа нужно вставлять контролируемую паузу.
В 1С 7.7 это можно сделать элегантным способом через открытие модального окна предупреждения с таймаутом:
// Пауза в 2 секунды между документами дает возможность СУБД обработать
// транзакции других пользователей и предотвращает эскалацию блокировок
Вопрос("Продолжить проведение?", "Да+Нет", 2);
Такой подход позволяет разгрузить транзакционную очередь СУБД, предоставляя другим пользователям приоритет при записи документов, хотя само восстановление последовательности при этом будет протекать значительно медленнее.
Используя приведенные методики и комбинируя их под специфику вашей конфигурации, вы сможете полностью контролировать время работы регламентных процедур и минимизировать простои пользователей.