Каждый разработчик и администратор баз данных «1С:Предприятие 8» рано или поздно сталкивается с механизмами последовательностей документов. Этот инструмент незаменим, когда требуется контролировать хронологическую актуальность расчетов — например, в партионном учете или при списании себестоимости. Однако иногда система начинает вести себя непредсказуемо: регламентное восстановление последовательности «зависает» часами, а простой запрос к таблице границ вместо одной ожидаемой строки возвращает сотни дублей.
В этой статье мы подробно разберем, почему происходит «размножение» строк в таблице границ последовательности (даже если у нее нет видимых измерений), к каким последствиям для производительности СУБД это приводит и как правильно исправить ситуацию штатными и хирургическими методами.
Чтобы понять природу проблемы, заглянем «под капот» платформы «1С:Предприятие 8». Для каждой последовательности, созданной в конфигураторе, СУБД резервирует две основные физические таблицы:
_Seq<n>) — в ней хранятся ссылки на документы, которые должны быть выстроены в хронологическом порядке, а также состояние их проведения._SeqB<n>) — именно здесь записывается точка актуальности (граница), до которой документы гарантированно проведены правильно. Граница состоит из полей периода (дата) и ссылки на документ-регистратор.Если в свойствах последовательности в конфигураторе не заданы Измерения (например, «Организация» или «Склад»), то с точки зрения логики СУБД в таблице границ должна существовать ровно одна строка. Эта строка определяет общую точку актуальности для всей информационной базы.
Но что делать, если запрос к виртуальной таблице Последовательность.ПартионныйУчет.Границы внезапно возвращает сотни строк с разными документами и датами? Давайте выясним основные причины этой аномалии.
Очень часто разработчики полагают, что у последовательности партионного учета нет измерений, поскольку они не видят их в пользовательском интерфейсе. Однако в конфигурациях старого поколения (таких как «Управление производственным предприятием 1.3» или «Комплексная автоматизация 1.1») у последовательностей могут присутствовать служебные измерения. Например, булево измерение ПроведенВХронологическойПоследовательности.
Когда программный код или внешняя обработка вызывает метод установки границы без явного указания структуры всех измерений, платформа ведет себя следующим образом:
// Неправильный вызов метода без учета структуры измерений
Последовательности.ПартионныйУчет.УстановитьГраницу(МоментВремени);
Если в структуре метаданных измерение существует, а в метод УстановитьГраницу() вторым параметром не передана структура отбора с конкретным значением этого измерения, платформа не может обновить существующую строку. Вместо операции обновления существующей записи (UPDATE) СУБД выполняет операцию вставки новой строки (INSERT) с дефолтными или пустыми значениями незаданных измерений. Повторение таких вызовов лавинообразно увеличивает количество строк в таблице _SeqB<n>.
Представим ситуацию: в процессе кастомизации базы разработчик удалил ранее существовавшее измерение последовательности (например, «Организация»), решив сделать последовательность общей.
При обновлении конфигурации базы данных платформа удаляет колонку измерения из SQL-таблицы границ. Однако физические строки, которые ранее различались по значению этого измерения, не всегда схлопываются в одну запись. В результате в SQL-таблице остаются дублирующие строки, у которых ключевые поля (теперь уже отсутствующие) стали неразличимы для платформы. При чтении через стандартный запрос 1С мы получаем множество одинаковых строк границ.
Если конфигурация работает в режиме разделения данных (например, в модели сервиса 1cFresh), платформа неявно добавляет во все таблицы базы данных, включая таблицы последовательностей, колонки разделителей (например, ОбластьДанныхОсновныеДанные). При определенных сбоях в работе разделения или некорректном выполнении регламентных заданий под полными правами без фильтрации областей в таблицу границ могут попасть записи, относящиеся к разным клиентам (тентантам), что визуально воспринимается как дублирование строк границ в рамках одного сеанса.
Когда вы запускаете стандартную процедуру восстановления последовательности:
Последовательности.ПартионныйУчет.Восстановить(МоментВремени);
Алгоритм платформы анализирует таблицу границ. Вместо того чтобы взять одну-единственную точку актуальности и начать последовательно проводить документы, идущие за ней, система видит, к примеру, 200 различных границ.
Платформа вынуждена инициировать тяжелый процесс расчета и проверки актуальности для каждой из 200 ложных границ в отдельности. Это приводит к следующим критическим последствиям:
Прибегать к прямому удалению записей в СУБД с помощью команды DELETE FROM sequencebound крайне не рекомендуется. Это нарушает целостность кэша платформы и может привести к непредсказуемым ошибкам в транзакциях. Рассмотрим штатные и безопасные способы лечения базы данных.
Если границы вашей последовательности окончательно запутались, самым простым и надежным решением будет полный программный сброс таблиц регистрации и границ с последующим заполнением.
Рассмотрим по шагам, как это сделать программно в режиме «1С:Предприятие»:
// Шаг 1. Полностью очищаем таблицы последовательности партионного учета
Последовательности.ПартионныйУчет.Очистить();
// Шаг 2. Программно заполняем таблицу регистрации заново нужными документами
// Например, выберем все проведенные документы поступления и реализации за период
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РеализацияТоваровУслуг.Ссылка КАК Ссылка,
| РеализацияТоваровУслуг.Дата КАК Дата
|ИЗ
| Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
|ГДЕ
| РеализацияТоваровУслуг.Проведен = ИСТИНА";
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
// Записываем документ в последовательность без перепроведения
Последовательности.ПартионныйУчет.Зарегистрировать(ВыборкаДетальныеЗаписи.Ссылка);
КонецЦикла;
Этот метод гарантирует, что таблица границ _SeqB<n> полностью очистится, и после первой же регистрации или ручной установки границы в ней появится ровно одна корректная строка.
Если вы не хотите писать программный код, можно принудительно заставить платформу реструктуризировать таблицы и удалить «осиротевшие» строки. Для этого:
В процессе реструктуризации и проверки логической целостности платформа 1С обнаружит несовпадение индексов и физически «схлопнет» некорректные записи в таблице границ, оставив только актуальные данные.
Если вы точно определили, какие именно технические измерения стали причиной размножения строк, можно принудительно схлопнуть дубли, записав в них пустую дату. Рассмотрим пример, когда у последовательности было измерение «Организация», которое начало дублировать записи:
// Создаем структуру отбора со старым (или пустым) разрезом измерения
Отбор = Новый Структура;
Отбор.Вставить("Организация", Справочники.Организации.ПустаяСсылка());
// Определяем пустой момент времени (начало времен)
ПустойМомент = Новый МоментВремени('00010101', Документы.РеализацияТоваровУслуг.ПустаяСсылка());
// Принудительно перезаписываем «мусорную» границу в базе данных
Последовательности.ПартионныйУчет.УстановитьГраницу(ПустойМомент, Отбор);
Этот код перезапишет проблемную строку. СУБД перестанет спотыкаться об нее при попытке рассчитать актуальное состояние последовательности документов.
Размножение границ последовательностей в 1С — неочевидная техническая проблема, способная парализовать расчет себестоимости на крупных предприятиях. Понимание принципов работы таблиц СУБД _SeqB<n> позволяет быстро диагностировать эту ошибку с помощью обычного консольного запроса. Помните, что регулярное проведение профилактических работ, таких как тестирование и исправление базы данных, а также аккуратное использование метода УстановитьГраницу() с указанием явной структуры измерений уберегут вашу систему от непредвиденных сбоев.