Как эффективно получать остатки товаров по складам в 1С:Управление торговлей 11.4, избегая проблем с производительностью?

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

При работе с крупными базами данных в 1С:Предприятии, особенно когда речь идет о получении остатков товаров по складам, часто возникают проблемы с производительностью. Стандартные запросы к регистрам накопления, таким как РегистрНакопления.ТоварыНаСкладах.Остатки, могут выполняться недопустимо долго, особенно если у нас десятки тысяч номенклатурных позиций и множество складов. В этой статье мы подробно разберем, как оптимизировать этот процесс, используя специализированные механизмы платформы 1С и конфигурации 1С:Управление торговлей 11.4 (УТ 11.4).

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

Анализируем проблему: почему стандартные запросы работают медленно?

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


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

Этот запрос, хотя и кажется логичным, может столкнуться с проблемами производительности по нескольким причинам:

  1. Объем данных: При большом количестве номенклатурных позиций, складов и характеристик, виртуальная таблица остатков должна обработать значительный объем данных для построения актуального среза.
  2. Параметры отбора: Хотя мы используем параметры &Дата и &СписокНоменклатуры, внутренняя логика построения виртуальной таблицы может быть неоптимальной для конкретных сценариев, особенно если список номенклатуры очень большой.
  3. Индексация: Несмотря на то что регистры накопления обычно имеют хорошие индексы, их эффективность может снижаться при сложных отборах или в сильно нагруженных системах. Важно убедиться, что индексы актуальны и соответствуют нашим запросам.
  4. Особенности платформы: Платформа 1С для работы с виртуальными таблицами остатков выполняет ряд внутренних операций, которые могут быть не самыми быстрыми в сравнении со специализированными API, разработанными для конкретных конфигураций.

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

Решение 1: Использование общего модуля УправлениеЗапасамиСервер.ПолучитьОстаткиТоваровНаСкладах()

Конфигурация 1С:Управление торговлей 11.4, как и другие современные типовые решения на базе управляемых форм, содержит множество оптимизированных функций для работы с данными. Одной из таких функций является ПолучитьОстаткиТоваровНаСкладах() из общего модуля УправлениеЗапасамиСервер.

Этот метод разработан специально для быстрого получения текущих остатков товаров. Он использует предопределенные запросы и механизмы платформы, которые зачастую оказываются гораздо быстрее, чем вручную написанные запросы к виртуальным таблицам.

Рассмотрим, как мы можем использовать эту функцию:

  1. Структура отбора: Функция принимает структуру с параметрами отбора, что позволяет нам гибко указывать, по какой номенклатуре, складам или другим измерениям мы хотим получить остатки.
  2. Дата среза: Мы можем указать конкретную дату, на которую хотим получить остатки.
  3. ТолькоВНаличии: Параметр, который позволяет нам получать только те позиции, которые физически есть на складе.
  4. СУчетомХарактеристик: Если в нашей номенклатуре используются характеристики, мы можем указать, что их тоже нужно учитывать.

Давайте посмотрим на пример кода, который демонстрирует использование этой функции:


// Это серверный код или код в обработке/отчете на сервере
// Предполагаем, что функция ПолучитьОстаткиТоваровПоСкладам является экспортной
// в каком-либо серверном модуле или вызывается напрямую в серверном контексте.
Функция ПолучитьОстаткиТоваровПоСкладам(СписокНоменклатуры, МассивСкладов, ДатаСреза, ТолькоВНаличии = Истина, СУчетомХарактеристик = Истина) Экспорт
    // Создаем структуру для передачи параметров отбора
    СтруктураОтбора = Новый Структура;
    
    // Если список номенклатуры передан и заполнен, добавляем его в отбор
    Если ЗначениеЗаполнено(СписокНоменклатуры) Тогда
        СтруктураОтбора.Вставить("Номенклатура", СписокНоменклатуры);
    КонецЕсли;
    
    // Если массив складов передан и заполнен, добавляем его в отбор
    Если ЗначениеЗаполнено(МассивСкладов) Тогда
        СтруктураОтбора.Вставить("Склад", МассивСкладов);
    КонецЕсли;

    // Вызываем функцию из общего модуля УправлениеЗапасамиСервер
    // Она возвращает ТаблицуЗначений с остатками
    Возврат УправлениеЗапасамиСервер.ПолучитьОстаткиТоваровНаСкладах(
        СтруктураОтбора,       // Параметры отбора (номенклатура, склады и т.д.)
        ДатаСреза,             // Дата, на которую получаем остатки
        ТолькоВНаличии,        // Истина, если нужны только физически имеющиеся товары
        СУчетомХарактеристик   // Истина, если учитывать характеристики номенклатуры
    );
КонецФункции

// Пример вызова этой функции из клиентского или серверного кода
&НаКлиенте
Процедура ПримерПолученияОстатковНаКлиенте(Команда)
    // Создаем список значений для отбора по номенклатуре
    СписокНоменклатурыДляОтбора = Новый СписокЗначений;
    // ... Здесь мы заполняем СписокНоменклатурыДляОтбора, например, из таблицы формы или другого источника ...
    // СписокНоменклатурыДляОтбора.Добавить(Справочники.Номенклатура.НайтиПоКоду("00001"));
    // СписокНоменклатурыДляОтбора.Добавить(Справочники.Номенклатура.НайтиПоКоду("00002"));

    // Создаем массив для отбора по складам
    МассивСкладовДляОтбора = Новый Массив;
    // ... Здесь мы заполняем МассивСкладовДляОтбора, например, из выбранных элементов формы ...
    // МассивСкладовДляОтбора.Добавить(Справочники.Склады.НайтиПоНаименованию("Основной склад"));
    // МассивСкладовДляОтбора.Добавить(Справочники.Склады.НайтиПоНаименованию("Склад готовой продукции"));
    
    // Вызываем серверную функцию для получения остатков
    // Передаем текущую дату в качестве даты среза
    РезультатТаблица = ПолучитьОстаткиТоваровПоСкладам(
        СписокНоменклатурыДляОтбора,
        МассивСкладовДляОтбора,
        ТекущаяДата(),
        Истина, // ТолькоВНаличии
        Истина  // СУчетомХарактеристик
    );
    
    // Далее мы можем обработать полученную таблицу значений
    // Например, вывести ее в табличное поле или использовать для дальнейших расчетов
    Если РезультатТаблица.Количество() > 0 Тогда
        Сообщить("Получено " + РезультатТаблица.Количество() + " строк остатков.");
        // Вы можете обойти РезультатТаблица для работы с данными
        // Для Каждого СтрокаОстатков Из РезультатТаблица Цикл
        //    Сообщить(СтрокаОстатков.Номенклатура + " на складе " + СтрокаОстатков.Склад + ": " + СтрокаОстатков.ВНаличии);
        // КонецЦикла;
    Иначе
        Сообщить("Остатки не найдены.");
    КонецЕсли;
КонецПроцедуры

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

Важный момент: Функция УправлениеЗапасамиСервер.ПолучитьОстаткиТоваровНаСкладах() ориентирована на получение показателя "ВНаличииОстаток". Если нам также необходим показатель "КОтгрузкеОстаток", нам понадобится более комплексное решение.

Решение 2: Получение товаров, доступных к отгрузке, с помощью СвободныеОстаткиСервер.ПолучитьСвободныеОстатки()

Показатель "КОтгрузкеОстаток" (или "свободный остаток") отличается от простого "ВНаличииОстаток" тем, что он учитывает не только физическое наличие товара на складе, но и его резервы под заказы покупателей, ожидаемые поступления и другие факторы, влияющие на реальную доступность товара для отгрузки. Если нам нужны именно эти данные, функция УправлениеЗапасамиСервер.ПолучитьОстаткиТоваровНаСкладах() будет недостаточной.

Для этих целей в 1С:УТ 11.4 предусмотрен еще один мощный механизм — ОбщийМодуль.СвободныеОстаткиСервер.ПолучитьСвободныеОстатки().

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

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


// Серверный код
Функция ПолучитьСвободныеОстаткиТоваров(СтруктураПараметров) Экспорт
    // СтруктураПараметров обычно содержит следующие ключи:
    // "Дата", "Склады", "Номенклатура", "Характеристики", "Назначение",
    // "ВидыЗапасов", "ВариантРасчета" и другие параметры отбора.
    // Пример СтруктурыПараметров:
    // СтруктураПараметров = Новый Структура;
    // СтруктураПараметров.Вставить("Дата", ТекущаяДата());
    // СтруктураПараметров.Вставить("Номенклатура", СписокНоменклатуры);
    // СтруктураПараметров.Вставить("Склады", МассивСкладов);
    // СтруктураПараметров.Вставить("ИспользоватьХарактеристики", Истина);
    // СтруктураПараметров.Вставить("ВариантРасчета", Перечисления.ВариантыРасчетаСвободныхОстатков.Доступно); // Например

    // Вызываем функцию из общего модуля СвободныеОстаткиСервер
    // Она возвращает ТаблицуЗначений с детальной информацией о свободных остатках
    Возврат СвободныеОстаткиСервер.ПолучитьСвободныеОстатки(СтруктураПараметров);
КонецФункции

// Пример вызова на клиенте (если функция экспортная в серверном модуле)
&НаКлиенте
Процедура ПримерПолученияСвободныхОстатковНаКлиенте(Команда)
    СписокНоменклатурыДляОтбора = Новый СписокЗначений;
    // ... заполняем СписокНоменклатурыДляОтбора ...

    МассивСкладовДляОтбора = Новый Массив;
    // ... заполняем МассивСкладовДляОтбора ...

    СтруктураПараметровРасчета = Новый Структура;
    СтруктураПараметровРасчета.Вставить("Дата", ТекущаяДата());
    СтруктураПараметровРасчета.Вставить("Номенклатура", СписокНоменклатурыДляОтбора);
    СтруктураПараметровРасчета.Вставить("Склады", МассивСкладовДляОтбора);
    СтруктураПараметровРасчета.Вставить("ИспользоватьХарактеристики", Истина);
    
    // Вариант расчета может быть "Доступно", "ВНаличии", "КОтгрузке" и т.д.
    // Для "КОтгрузке" часто подходит "Доступно" или похожие варианты в зависимости от версии УТ.
    // Необходимо изучить Перечисления.ВариантыРасчетаСвободныхОстатков в вашей конфигурации.
    // Пример: СтруктураПараметровРасчета.Вставить("ВариантРасчета", Перечисления.ВариантыРасчетаСвободныхОстатков.Доступно);

    РезультатСвободныхОстатков = ПолучитьСвободныеОстаткиТоваров(СтруктураПараметровРасчета);

    Если РезультатСвободныхОстатков.Количество() > 0 Тогда
        Сообщить("Получено " + РезультатСвободныхОстатков.Количество() + " строк свободных остатков.");
        // РезультатСвободныхОстатков будет содержать колонки типа "Номенклатура", "Склад", "Характеристика",
        // "КоличествоДоступно", "КоличествоКОтгрузке", "КоличествоВРезерве" и т.п., в зависимости от параметров и конфигурации.
        // Для Каждого СтрокаСвободныхОстатков Из РезультатСвободныхОстатков Цикл
        //    Сообщить("Номенклатура: " + СтрокаСвободныхОстатков.Номенклатура + ", Доступно: " + СтрокаСвободныхОстатков.КоличествоДоступно);
        // КонецЦикла;
    Иначе
        Сообщить("Свободные остатки не найдены.");
    КонецЕсли;
КонецПроцедуры

Изучите структуру Перечисления.ВариантыРасчетаСвободныхОстатков в вашей конфигурации, чтобы выбрать наиболее подходящий вариант для вашего сценария ("КОтгрузке", "Доступно" и т.п.). Этот метод позволяет получить не только количество, которое можно отгрузить, но и другие связанные показатели, что делает его чрезвычайно гибким и мощным инструментом.

Преимущества использования СвободныеОстаткиСервер.ПолучитьСвободныеОстатки():

  1. Комплексность: Учитывает широкий спектр факторов (наличие, резервы, ожидания) для точного расчета доступности.
  2. Производительность: Как и предыдущий метод, он оптимизирован разработчиками 1С для работы с большими объемами данных.
  3. Гибкость: Позволяет настраивать параметры расчета и отбора, получая именно те данные, которые нам нужны.

В итоге, использование СвободныеОстаткиСервер.ПолучитьСвободныеОстатки() позволяет полностью решить проблему с получением показателя "КОтгрузкеОстаток", при этом сохраняя высокую производительность.

Дополнительные рекомендации по оптимизации

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

  1. Актуализация индексов базы данных: Регулярно проверяйте и перестраивайте индексы вашей базы данных. Устаревшие или фрагментированные индексы могут значительно замедлять выполнение запросов. Это задача для системного администратора или специалиста по обслуживанию СУБД.
  2. Оптимизация параметров запроса: Если вы все же используете прямые запросы к регистрам, максимально используйте параметры запроса (ГДЕ, В, МЕЖДУ) для сужения выборки до необходимого минимума. Избегайте полных сканирований таблиц.
  3. Использование временных таблиц: Для сложных запросов, включающих несколько источников данных, мы можем использовать временные таблицы (ПОМЕСТИТЬ в запросе) для поэтапного формирования результата. Это позволяет разбить сложный запрос на несколько более простых, которые могут быть выполнены эффективнее.
  4. Режим работы с данными: В некоторых случаях, если нам не нужны данные в реальном времени, а достаточно периодического обновления, мы можем рассмотреть вариант с предварительным расчетом и кэшированием остатков в отдельном регистре или таблице.
  5. Виртуальная таблица ОстаткиИОбороты: Для получения среза остатков и оборотов за период, виртуальная таблица ОстаткиИОбороты может быть более эффективной, чем просто Остатки, так как она часто использует предоптимизированные алгоритмы. Однако для моментального среза на текущую дату специализированные функции конфигурации обычно показывают лучшую производительность.
  6. Анализ плана запроса: При возникновении проблем с производительностью запросов, всегда полезно проанализировать план выполнения запроса в консоли запросов или средствами СУБД. Это поможет нам выявить "узкие места" и понять, какая часть запроса выполняется дольше всего.

Итоги и заключение

В этой статье мы подробно рассмотрели, как эффективно решать проблему медленного получения остатков товаров по складам в 1С:Управление торговлей 11.4. Мы выяснили, что наиболее производительным и надежным способом является использование специализированных функций конфигурации, таких как УправлениеЗапасамиСервер.ПолучитьОстаткиТоваровНаСкладах() для получения наличия и СвободныеОстаткиСервер.ПолучитьСвободныеОстатки() для получения данных, доступных к отгрузке.

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

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

← На главную