Как реализовать хранение истории состояний объектов в 1С 7.7 на SQL без потери производительности?

Программист 1С v7.7 Управленческий учет IT и автоматизация бизнеса
← На главную

В крупных информационных системах на базе 1С 7.7 часто возникает задача отслеживания изменений: кто, когда и что именно поменял в объекте (справочнике или документе). Ситуация осложняется, когда база работает на MS SQL Server, объем событий исчисляется миллионами, а требования к быстродействию системы крайне высоки. В версии 7.7 отсутствуют штатные механизмы вроде "Регистров сведений" или встроенного версионирования, поэтому разработчикам приходится выбирать между несколькими архитектурными решениями. Проанализируем наиболее эффективные подходы.

Решение 1: Использование служебного справочника

Это самый простой в реализации метод, который остается в рамках штатных метаданных 1С. Мы создаем справочник (например, ИсторияСостояний), где каждый элемент — это запись об изменении. Рассмотрим ключевые моменты настройки такого справочника:

  1. Оптимизация структуры: Чтобы справочник не тормозил, длину кода и наименования можно выставить в ноль, если они не нужны. Основные данные хранятся в реквизитах.
  2. Индексация: Обязательно устанавливаем флаг "Сортировка" (индексация) для реквизитов ДатаСобытия и Объект. Это позволит SQL-серверу быстро фильтровать записи при построении отчетов.
  3. Формат даты и времени: В 1С 7.7 есть особенности работы с временем. Для удобства сортировки можно создать строковый реквизит и записывать туда дату и время в формате ГГГГММДД ЧЧ:ММ:СС.

Разберем пример кода в модуле формы или объекта при записи:


Процедура ПриЗаписи()
    СпрИстория = СоздатьОбъект("Справочник.ИсторияСостояний");
    СпрИстория.Новый();
    СпрИстория.Объект = ТекущийОбъект;
    СпрИстория.ДатаСобытия = РабочаяДата();
    СпрИстория.ВремяСобытия = ТекущееВремя();
    СпрИстория.Автор = ИмяПользователя();
    СпрИстория.Состояние = СостояниеОбъекта;
    СпрИстория.Записать();
КонецПроцедуры

Решение 2: Прямые SQL-запросы и внешние таблицы

Если предполагается хранение миллионов записей за несколько лет, стандартные справочники могут замедлить реструктуризацию базы. Проанализируем более продвинутый вариант — использование внешних таблиц, о которых 1С "не знает" на уровне конфигуратора.

Для этого используется внешняя компонента 1C++. Мы создаем таблицу непосредственно в SQL-базе. Это позволяет избежать блокировок системных таблиц 1С (таких как _1SJOURN) при интенсивной записи логов. Рассмотрим, как может выглядеть запись в такую таблицу:


// Пример записи через 1C++ и прямой SQL
ТекстЗапроса = "
|INSERT INTO Custom_ObjectHistory (ObjID, UserID, DateEvent, NewState)
|VALUES (:ID, :User, :Date, :State)";
db = СоздатьОбъект("ODBCDatabase");
Запрос = СоздатьОбъект("ODBCRecordset");
Запрос.УстБазу(db);
Запрос.УстановитьТекстовыйПараметр("ID", ТекущийЭлемент());
Запрос.УстановитьТекстовыйПараметр("User", ИмяПользователя());
Запрос.УстановитьТекстовыйПараметр("Date", ТекущаяДата());
Запрос.УстановитьТекстовыйПараметр("State", НужноеСостояние);
Запрос.ВыполнитьИнструкцию(ТекстЗапроса);

Важное преимущество: Записи в такую таблицу можно делать асинхронно или через триггеры SQL, что практически не влияет на скорость работы пользователя в интерфейсе.

Решение 3: Текстовое логирование с последующей загрузкой

Выясним причину, по которой запись напрямую в базу в момент транзакции может быть нежелательна: если запись объекта "откатится" из-за ошибки, запись в справочнике истории (если она внутри транзакции) тоже исчезнет. Если же нам нужен "черный ящик", который фиксирует все попытки, или если мы хотим максимально разгрузить SQL в пиковые часы, используем текстовые файлы.

Рассмотрим алгоритм этого метода:

  1. В момент изменения объекта 1С пишет строку в локальный или сетевой текстовый файл (CSV или JSON-подобный формат). Операция записи в файл происходит мгновенно и не блокирует таблицы БД.
  2. Раз в сутки (например, ночью) регламентное задание считывает все накопленные файлы и одной массовой транзакцией загружает их в SQL-таблицу истории.
  3. После загрузки файлы удаляются.

Решение 4: Дельта-логирование (хранение только изменений)

Чтобы база не раздувалась, не стоит записывать все состояние объекта целиком. Рациональнее хранить только те реквизиты, которые реально изменились. Для этого перед записью необходимо сравнить текущие значения с теми, что уже лежат в базе.

Рассмотрим пример функции сравнения:


Функция ПолучитьИзменения()
    ТекстИзменений = "";
    СтарыйОбъект = СоздатьОбъект("Справочник." + Вид());
    Если СтарыйОбъект.НайтиЭлемент(ТекущийЭлемент()) = 1 Тогда
        Если СтарыйОбъект.Наименование <> Наименование Тогда
            ТекстИзменений = ТекстИзменений + "Наим: " + СтарыйОбъект.Наименование + " -> " + Наименование + "; ";
        КонецЕсли;
        // Проверка остальных реквизитов...
    КонецЕсли;
    Возврат ТекстИзменений;
КонецФункции

Оптимизация хранения и обслуживания (SQL-уровень)

Для обеспечения стабильной работы системы в течение 3–5 лет и более, проанализируем настройки на стороне сервера баз данных:

Секционирование таблиц (Partitioning): Если вы используете внешнюю таблицу для истории, настройте её секционирование по годам или месяцам. Это позволит хранить старые данные на медленных дешевых дисках, а актуальные — на SSD. При этом для 1С таблица останется единым объектом.

Индексы покрывающего типа: При создании индексов на таблицу истории в SQL Server, включайте в индекс часто запрашиваемые поля (например, NewValue). Это позволит SQL-серверу формировать отчеты по истории, не обращаясь к основной таблице (Index Only Scan), что ускоряет построение отчетов в десятки раз.

Проблема удаления объектов: Помните, что в 1С 7.7 при удалении элемента справочника его история может стать "бесполезной", так как ссылка превратится в "Объект не найден". Чтобы избежать этого, при записи события в историю всегда сохраняйте текстовое представление объекта (его код или наименование) в отдельном поле. Таким образом, даже через 5 лет вы сможете понять, к какому объекту относилась эта запись, даже если сам объект был удален.

Подводя итог, для реализации истории в 1С 7.7 лучшим балансом между сложностью и эффективностью является использование индексированного справочника. Однако для систем с экстремальной нагрузкой следует смотреть в сторону прямых запросов через 1C++ к отдельным SQL-таблицам вне метаданных.

← На главную