Почему тормозит печать чека при запросе цен в 1С и как это исправить

Программист 1С v8.3 (Обычные формы) Управленческий учет Торговля и дистрибуция
← На главную

В розничной торговле на базе решений 1С (будь то «1С:Управление торговым предприятием», «1С:Комплексная автоматизация» или «1С:Управление торговлей») скорость пробития чека является критически важным фактором. Задержка даже в 10–15 секунд перед печатью чека создает очереди и вызывает раздражение покупателей. Что же делать, если замер производительности показывает зависание на простом и стандартном запросе цен, который в тестовой базе под полными правами «летает» за доли секунды, а на рабочем месте кассира выполняется от 30 секунд до 2 минут?

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

Выясняем причину: почему «ломается» СрезПоследних при RLS

Для начала проанализируем типовой запрос получения розничных цен из регистра сведений ЦеныАТТ (цены в автоматизированных торговых точках), который обычно используется при заполнении и пробитии чека ККМ:


ВЫБРАТЬ
    ЦеныПродажные.Склад КАК Склад,
    ЦеныПродажные.Номенклатура КАК Номенклатура,
    ЦеныПродажные.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
    ЦеныПродажные.Цена КАК Цена
ИЗ
    РегистрСведений.ЦеныАТТ.СрезПоследних(
            &Дата,
            Склад В (&СписокСкладов)
                И Номенклатура В (&СписокНоменклатуры)) КАК ЦеныПродажные

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

Причина кроется в механизме RLS (Row-Level Security) — ограничении доступа на уровне записей. Рассмотрим детально физику этого процесса:

  1. Сложная природа виртуальной таблицы: Виртуальная таблица СрезПоследних не существует в базе данных в готовом виде (если не включена специальная опция итогов). Чтобы ее рассчитать, СУБД выполняет внутреннее соединение физической таблицы регистра самой с собой, вычисляя максимальный период (срез) для каждой уникальной комбинации измерений на указанную дату.
  2. Модификация запроса платформой: Когда пользователь с ограниченными правами (например, кассир, у которого настроена видимость только определенных складов или контрагентов) выполняет запрос, платформа 1С на лету переписывает его. Она внедряет в тело запроса дополнительные подзапросы и условия JOIN к таблицам прав доступа, проверяя каждую запись номенклатуры и склада на соответствие разрешенным шаблонам.
  3. Слабость файлового движка 1С: В отличие от серверных СУБД (MS SQL, PostgreSQL), встроенная файловая база данных 1С (формат .1CD) имеет очень простой оптимизатор запросов. Столкнувшись со сложным вложенным запросом, где соединяются виртуальная таблица СрезПоследних и динамические условия RLS, файловый оптимизатор «теряется». Вместо использования индексов он переходит к полному сканированию таблиц (Table Scan). Система начинает последовательно перебирать весь регистр сведений, что и приводит к задержкам в минуты.
  4. Эффект «свернутой» базы: При свертке базы данных все прошлые движения сворачиваются, и создаются новые крупные документы ввода остатков или установки цен. Если в старой базе записи были «размазаны» по времени, то в новой свернутой базе огромное количество цен записывается на одну секунду. Это создает колоссальную плотность записей на одну точку времени, что делает расчет среза последних для СУБД под RLS непосильной задачей.

---

Способы решения проблемы

Рассмотрим по шагам практические методы устранения этой проблемы, начиная с самых простых и эффективных.

Решение 1. Использование привилегированного режима (Рекомендуется)

Пробитие чека — это строго регламентированная операция. Кассиру в момент печати чека не требуется интерактивно ограничивать видимость цен. База данных должна просто быстро выдать цену для конкретного товара. Мы можем временно отключить проверку RLS на время выполнения этого критического запроса.

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

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


// Устанавливаем привилегированный режим, отключая проверку RLS
УстановитьПривилегированныйРежим(Истина);

// Выполняем запрос получения цен
Выборка = Запрос.Выполнить().Выбрать();

// Обязательно возвращаем обычный режим работы программы
УстановитьПривилегированныйРежим(Ложь);

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

Решение 2. Включение опции «Разрешить итоги: Срез последних»

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

Выполним следующие действия в конфигураторе:

  1. Найдем в дереве метаданных регистр сведений ЦеныАТТ.
  2. Откроем его свойства и перейдем на вкладку «Данные» (или «Основные» в зависимости от версии платформы).
  3. Установим флаг «Разрешить итоги: Срез последних».

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

РегистрыСведений.ЦеныАТТ.УстановитьИспользованиеИтоговСрезаПоследних(Истина);

Почему это помогает? После включения этой опции СУБД больше не будет динамически рассчитывать срез последних путем тяжелого соединения таблиц. Платформа создаст в файле базы данных дополнительную физическую таблицу итогов среза. Запрос будет обращаться напрямую к ней, и даже при наложении RLS файловый оптимизатор сможет быстро отработать по индексам этой готовой таблицы.

Решение 3. Оптимизация запроса через Временные Таблицы

Если архитектура конфигурации не позволяет использовать привилегированный режим, нам придется помочь оптимизатору СУБД и переписать исходный запрос. Главная задача — максимально ограничить выборку данных до того, как к ней применится RLS.

Разберем по шагам правильное построение пакета запросов с использованием временных таблиц:


// Создаем менеджер временных таблиц
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;

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

// Передаем параметры
Запрос.УстановитьПараметр("ТаблицаТоваровЧека", ТаблицаТоваровЧека);
Запрос.Выполнить();

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

РезультатЗапроса = Запрос.Выполнить();

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

Решение 4. Очистка и пересчет ключей доступа RLS

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

Проделаем следующие регламентные действия:

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

---

Резюме

Мы выяснили, что причиной зависания при печати чеков является не размер базы данных и не сам запрос цен, а сочетание трех факторов: файловый режим работы + использование RLS + виртуальная таблица СрезПоследних.

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

← На главную