Что выбрать для работы с многомиллионным регистром: виртуальные таблицы или физическую таблицу движений?

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

При работе с высоконагруженными системами на базе 1С:Предприятие 8, где количество записей в регистрах накопления исчисляется миллионами и десятками миллионов, перед разработчиком неизбежно встает вопрос: использовать ли стандартные виртуальные таблицы (Остатки, Обороты, ОстаткиИОбороты) или писать запросы напрямую к физической таблице движений? Существует мнение, что «прямой» запрос к физике может быть быстрее, однако на практике всё гораздо сложнее. В этой статье мы подробно разберем внутренние механизмы платформы, проанализируем разницу в поведении СУБД и выясним, как правильно строить запросы к большим данным.

Внутренняя механика: как работают виртуальные таблицы

Для начала разберем, что происходит «под капотом», когда мы обращаемся к виртуальной таблице. Платформа 1С не хранит данные виртуальных таблиц в готовом виде в базе данных (за исключением текущих итогов). Вместо этого она динамически формирует SQL-запрос, комбинируя данные из нескольких физических таблиц. Рассмотрим этот процесс на примере регистра остатков.

Физически в СУБД для регистра остатков существуют:

  1. Таблица движений (основная физическая таблица).
  2. Таблица итогов (хранит рассчитанные остатки на начало каждого месяца).

Когда мы запрашиваем виртуальную таблицу Остатки на определенную дату, система выполняет следующий алгоритм:

  1. Выбирает ближайшие рассчитанные итоги на начало месяца, в который попадает искомая дата.
  2. Добавляет (или вычитает) к этим итогам все движения из физической таблицы за период от начала этого месяца до указанной в параметрах даты.

Выясним причину, почему это эффективно: если в регистре накоплены данные за 5 лет, нам не нужно суммировать миллионы записей с самого начала ведения учета. Платформа берет «точку опоры» в таблице итогов и добирает лишь малую часть данных из таблицы движений. Если же мы обратимся к физической таблице напрямую и попробуем посчитать остаток через СУММА(СуммаОстаток), нам придется самостоятельно описывать всю логику агрегации, что крайне трудозатратно и часто ведет к ошибкам.

Особенности работы на PostgreSQL и MSSQL

Проанализируем ситуацию, описанную многими разработчиками: почему на PostgreSQL запросы к виртуальным таблицам иногда работают медленнее, чем на MSSQL? Причина кроется в особенностях оптимизаторов запросов этих СУБД.

Платформа 1С транслирует обращение к виртуальной таблице в сложный SQL-запрос с вложенными подзапросами (Subqueries). Оптимизатор MSSQL обычно успешно «проглатывает» такие конструкции, эффективно пробрасывая фильтры по измерениям (например, по Номенклатуре или Складу) внутрь подзапроса. Это позволяет СУБД сканировать только нужные фрагменты индексов.

PostgreSQL в некоторых случаях воспринимает вложенный запрос как «черный ящик». Вместо того чтобы сначала отфильтровать данные по конкретной номенклатуре, он может попытаться рассчитать итоги по всему регистру в памяти, а уже потом наложить фильтр. На многомиллионном регистре это приводит к колоссальным задержкам и деградации производительности.

Золотое правило: использование временных таблиц

Чтобы избежать проблем с производительностью (особенно на PostgreSQL), разберем стандартный метод, который часто называют «фэн-шуй в 1С». Суть его заключается в изоляции виртуальной таблицы от остальной логики запроса.

Рассмотрим пошагово правильный алгоритм построения сложного запроса:

  1. Выборка во временную таблицу: Сначала мы получаем данные только из виртуальной таблицы с наложением всех необходимых фильтров в параметрах самой таблицы. Результат помещаем во временную таблицу.
  2. Индексация: Обязательно индексируем временную таблицу по полям, которые будут участвовать в дальнейших соединениях.
  3. Соединение: В основном запросе соединяем уже готовую временную таблицу с другими данными.

Посмотрим на пример кода, иллюстрирующий этот подход:


// Шаг 1: Получаем данные из виртуальной таблицы во временную
Запрос.Текст = 
"ВЫБРАТЬ
|	РегистрОстатки.Номенклатура КАК Номенклатура,
|	РегистрОстатки.КоличествоОстаток КАК Остаток
|ПОМЕСТИТЬ ВТ_Остатки
|ИЗ
|	РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, Номенклатура В (&МассивНоменклатуры)) КАК РегистрОстатки
|ИНДЕКСИРОВАТЬ ПО
|	Номенклатура";

// Шаг 2: Работаем с подготовленными данными
Запрос.Текст = Запрос.Текст + 
"ВЫБРАТЬ
|	ВТ_Остатки.Номенклатура,
|	ВТ_Остатки.Остаток,
|	Цены.Цена
|ИЗ
|	ВТ_Остатки КАК ВТ_Остатки
|ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ) КАК Цены
|ПО ВТ_Остатки.Номенклатура = Цены.Номенклатура";

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

Виртуальная таблица против физической: когда «физика» уместна?

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

Важный нюанс: при работе с физической таблицей разработчики часто забывают про поле Активность (_Active в терминах СУБД). Виртуальные таблицы учитывают его автоматически, отсекая сторнированные или помеченные на удаление движения. В физической таблице фильтр ГДЕ Активность = ИСТИНА нужно накладывать вручную.

Регистры оборотов: есть ли разница?

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

Если итоги оборотов включены, виртуальная таблица Обороты работает аналогично остаткам — использует агрегаты за месяц. Если итоги выключены, виртуальная таблица превращается в обычный SELECT SUM(...) из физической таблицы. В этом случае разницы в производительности между ВТ и ФТ практически нет, но использование ВТ все равно предпочтительнее с точки зрения чистоты кода и автоматической фильтрации по активности записей.

Современные возможности (платформа 8.3.22 и выше)

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

Также не забывайте про режим Разделения итогов. На многомиллионных регистрах, куда идет интенсивная запись, этот механизм позволяет избежать блокировок таблицы итогов. Хотя это больше влияет на скорость записи, косвенно это ускоряет и чтение, так как уменьшается время ожидания освобождения ресурсов СУБД.

Подведем итоги

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

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

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

← На главную