Как реализовать периодичность регистра сведений с точностью менее одной секунды

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе разработки на платформе 1С:Предприятие программисты часто сталкиваются со стандартным ограничением типа данных Дата. В системе 1С этот тип данных всегда хранит время с точностью до секунды. Это накладывает ограничение на использование периодических регистров сведений: вы не можете штатно записать две разные записи в одну секунду для одного набора измерений, так как система посчитает их дублями или просто перезапишет старую запись новой.

Такая потребность возникает при создании систем высокочастотного логирования, протоколирования обменов данными, записи замеров производительности или при работе с внешним оборудованием. Разберем подробно, как обойти это ограничение и реализовать «сверхсекундную» точность.

Метод 1. Добавление дополнительного измерения точности

Проанализируем самый распространенный и надежный способ. Поскольку мы не можем изменить поведение системного поля Период, нам необходимо создать структуру, которая позволит различать записи внутри одной секунды. Для этого мы создаем непериодический регистр сведений (или оставляем его периодическим, если это удобно, но добавляем уникальный ключ).

Рассмотрим по шагам добавление измерения для хранения долей секунды:

  1. Создаем регистр сведений и устанавливаем признак Независимый.
  2. Добавляем стандартное измерение ДатаСобытия с типом Дата (состав даты — Дата и время).
  3. Добавляем второе измерение Миллисекунды (или Микросекунды) с типом Число. Длина — 3 (для миллисекунд) или 6 (для микросекунд), точность — 0, неотрицательное.

Теперь в программном коде при записи данных мы будем разделять время на две составляющие. Посмотрим на пример кода получения точного времени:


// Получаем текущую универсальную дату в миллисекундах (доступно в новых версиях платформы)
ВсегоМиллисекунд = ТекущаяУниверсальнаяДатаВМиллисекундах();

// Вычисляем компоненты для записи
ТекущаяДатаСекунды = ТекущаяДата(); // Стандартная дата
ДолиСекунды = ВсегоМиллисекунд % 1000; // Остаток от деления — это наши миллисекунды

// Запись в регистр
МенеджерЗаписи = РегистрыСведений.НашЛогСобытий.СоздатьМенеджерЗаписи();
МенеджерЗаписи.ДатаСобытия = ТекущаяДатаСекунды;
МенеджерЗаписи.Миллисекунды = ДолиСекунды;
// ... заполнение остальных измерений и ресурсов
МенеджерЗаписи.Записать();

Метод 2. Использование индекса или порядкового номера

В ситуациях, когда нам не важна астрономическая точность (конкретная миллисекунда), а важна лишь последовательность записей внутри одной секунды, можно использовать измерение-счетчик. Рассмотрим ситуацию: в одну секунду происходит 10 событий. Нам нужно, чтобы они выстроились в строгом порядке.

В этом случае мы добавляем измерение Порядок (тип Число). При записи каждой следующей порции данных в рамках одной транзакции или одного процесса мы инкрементируем это число. Это гарантирует уникальность ключа записи и позволяет сортировать данные в правильном хронологическом порядке.

Метод 3. Изучение опыта БСП (Библиотека стандартных подсистем)

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

Для получения таких данных используются специализированные функции платформы. Рассмотрим пример получения момента времени высокой точности:


// Использование встроенной функции платформы для высокоточных замеров
МоментНачала = ТекущаяУниверсальнаяДатаВМиллисекундах();
// Выполнение полезной нагрузки
// ...
МоментОкончания = ТекущаяУниверсальнаяДатаВМиллисекундах();

Продолжительность = МоментОкончания - МоментНачала;

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

Реализация «Среза последних» для непериодического регистра

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

Нам потребуется использовать вложенный запрос для поиска максимального момента времени. Проанализируем этот алгоритм:


ВЫБРАТЬ
    МаксимальныеДаты.Измерение1,
    МАКС(Лог.Миллисекунды) КАК МаксМиллисекунды
ПОМЕСТИТЬ ВТ_МаксимальныеМоменты
ИЗ
    (ВЫБРАТЬ
        Измерение1,
        МАКС(ДатаСобытия) КАК МаксДата
    ИЗ
        РегистрСведений.НашЛогСобытий
    ГРУППИРОВАТЬ ПО
        Измерение1) КАК МаксимальныеДаты
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НашЛогСобытий КАК Лог
    ПО МаксимальныеДаты.Измерение1 = Лог.Измерение1
    И МаксимальныеДаты.МаксДата = Лог.ДатаСобытия
ГРУППИРОВАТЬ ПО
    МаксимальныеДаты.Измерение1;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    Регистр.ДатаСобытия,
    Регистр.Миллисекунды,
    Регистр.РесурсЗначение
ИЗ
    РегистрСведений.НашЛогСобытий КАК Регистр
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_МаксимальныеМоменты КАК Тмп
    ПО Регистр.Измерение1 = Тмп.Измерение1
    И Регистр.Миллисекунды = Тмп.МаксМиллисекунды

Важный нюанс: Для обеспечения высокой скорости таких запросов необходимо, чтобы измерения ДатаСобытия и Миллисекунды были проиндексированы. В настройках регистра сведений установите свойство Индексировать у соответствующих полей.

Важные рекомендации по производительности и надежности

При работе с высокочастотными регистрами следует учитывать несколько критических факторов:

  1. Транзакции и откаты: Помните, что запись в регистр сведений — это транзакционная операция. Если в процессе работы произойдет ошибка и транзакция откатится, ваши логи (записанные в регистр) также исчезнут. Если вам нужно логировать именно процесс падения системы, используйте запись в текстовые файлы, так как они не зависят от транзакций БД.
  2. GUID для уникальности: Иногда вместо миллисекунд используют тип УникальныйИдентификатор. Это гарантирует, что записи никогда не совпадут, однако GUID не обеспечивает хронологического порядка при сортировке. Поэтому для временных шкал лучше использовать именно числовые микросекунды или инкрементный индекс.
  3. Объем данных: Запись данных чаще раза в секунду очень быстро раздувает размер базы данных. Продумайте механизмы очистки (свертки) старых записей в таких регистрах, чтобы база не росла бесконтрольно.

Подводя итог, можно сказать: хотя штатного механизма «миллисекундного периода» в 1С нет, комбинация непериодического регистра и дополнительного числового измерения полностью решает задачу, обеспечивая при этом высокую производительность и точность данных.

← На главную