Как оптимизировать отчет по анализу кросс-продаж в 1С при ошибке «Недостаточно памяти»?

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

При разработке отчетов для анализа «корзины покупателя» или кросс-наполненности чеков (совместных продаж товаров) программисты 1С часто сталкиваются с критической ошибкой «Недостаточно памяти». Эта проблема особенно актуальна для конфигураций уровня 1С:Управление нашей фирмой (УНФ), 1С:Розница или 1С:Управление торговлей, когда расчет производится за длительный период (месяц, квартал) по всем торговым точкам сразу. Основная причина кроется в архитектуре запроса: использование самосоединения (Self-Join) таблиц приводит к геометрическому росту объема данных, который не может быть обработан в оперативной памяти.

Рассмотрим детально, как оптимизировать такой отчет, разобрав причины возникновения ошибки и пошаговые методы улучшения производительности системы компоновки данных (СКД) и SQL-запросов.

Выявление причины: почему «падает» самосоединение?

Проанализируем ситуацию: для того чтобы понять, какие товары покупали вместе с «Номенклатурой А», нам нужно соединить таблицу продаж саму с собой по полю Документ (чек), исключив совпадение самой номенклатуры. Если в чеке содержится 10 позиций, то при самосоединении система создаст 100 строк для этого одного чека. Если в базе данных десятки тысяч чеков, объем промежуточных данных во временных таблицах или в памяти SQL-сервера достигает десятков гигабайт. Стандартные механизмы СКД при включенном автозаполнении только усугубляют ситуацию, добавляя неявные соединения для получения представлений ссылок.

Шаг 1. Использование временных таблиц и индексация

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

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

  1. Выберем необходимые данные из регистра накопления во временную таблицу.
  2. Обязательно проиндексируем временную таблицу по полям, по которым будет происходить соединение.
  3. Выполним соединение уже подготовленных и проиндексированных данных.

Пример оптимизированного запроса для подготовки данных:


ВЫБРАТЬ
    ПродажиОбороты.Номенклатура КАК Номенклатура,
    ПродажиОбороты.Документ КАК Документ
ПОМЕСТИТЬ ВТПродажиОбороты
ИЗ
    РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, , Документ ССЫЛКА Документ.ЧекККМ) КАК ПродажиОбороты
ИНДЕКСИРОВАТЬ ПО
    Документ,
    Номенклатура;

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

Шаг 2. Оптимизация соединений и условий

Рассмотрим, как правильно выполнить самосоединение. Вместо использования ПОЛНОЕ СОЕДИНЕНИЕ, которое крайне ресурсозатратно, следует использовать ЛЕВОЕ СОЕДИНЕНИЕ, если нам важен первичный список товаров, или ВНУТРЕННЕЕ СОЕДИНЕНИЕ, если мы ищем только факты совместных покупок.

Также проанализируем использование функции ВЫРАЗИТЬ. Поле Документ в регистрах часто имеет составной тип. Если мы точно знаем, что работаем только с чеками, явное приведение типа ускоряет работу запроса:


ВЫБРАТЬ
    ВТПродажиОбороты.Номенклатура КАК Номенклатура,
    ЕСТЬNULL(ВТПродажиОбороты1.Номенклатура, ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)) КАК НоменклатураКолонка,
    КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ВТПродажиОбороты.Документ) КАК КоличествоЧеков
ИЗ
    ВТПродажиОбороты КАК ВТПродажиОбороты
        ЛЕВОЕ СОЕДИНЕНИЕ ВТПродажиОбороты КАК ВТПродажиОбороты1
        ПО ВТПродажиОбороты.Документ = ВТПродажиОбороты1.Документ
            И ВТПродажиОбороты.Номенклатура <> ВТПродажиОбороты1.Номенклатура
СГРУППИРОВАТЬ ПО
    ВТПродажиОбороты.Номенклатура,
    ЕСТЬNULL(ВТПродажиОбороты1.Номенклатура, ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка))

Шаг 3. Управление настройками СКД

Выясним причину, почему запрос в консоли запросов работает быстро, а в СКД выдает ошибку памяти. Система компоновки данных выполняет «трансформацию» вашего запроса:

  1. Автозаполнение: СКД автоматически добавляет в ВЫБРАТЬ и СГРУППИРОВАТЬ поля представлений (ПРЕДСТАВЛЕНИЕССЫЛКИ) для каждой ссылки. Если ссылок много (номенклатура, категории, склады), количество полей в GROUP BY вырастает в разы, что критично для памяти. Попробуйте отключить автозаполнение и прописать нужные поля вручную.
  2. Условное оформление: Большое количество правил условного оформления, наложенных на детальные записи или группировки, может потреблять значительные ресурсы клиента. Попробуйте временно отключить его для диагностики.
  3. Параметры виртуальных таблиц: Убедитесь, что отборы (по складу, периоду) передаются именно в параметры виртуальной таблицы &НачалоПериода, &КонецПериода, а не накладываются позже в секции ГДЕ.

Шаг 4. Использование механизмов интеллектуального анализа (Apriori)

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

Преимущества метода:

Шаг 5. Радикальная оптимизация через дополнительный регистр

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

Как это работает:

  1. При проведении чека ККМ (в фоновом задании или подписке на событие) программно вычисляются все пары товаров в чеке.
  2. В регистр записываются данные: Товар1, Товар2, Период, КоличествоЧеков.
  3. Отчет в СКД превращается в простейшую выборку из этого регистра без каких-либо соединений.

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

Рекомендации по системным настройкам

Выясним, влияет ли разрядность клиента на ошибку. Если вы используете 32-битный клиент 1С, он ограничен лимитом адресного пространства в 2-3 ГБ. При формировании больших таблиц в СКД этот лимит исчерпывается мгновенно. Использование 64-битного клиента 1С позволяет отчету задействовать всю доступную оперативную память сервера или рабочей станции, что часто является «быстрым решением» проблемы без переписывания кода.

Подведем итог: для оптимизации отчета по кросс-продажам необходимо использовать временные таблицы с составными индексами, ограничивать выборку по типам документов через ВЫРАЗИТЬ, минимизировать количество полей в группировках СКД и, при экстремальных объемах данных, переходить к использованию специализированных регистров или механизмов анализа данных платформы.

← На главную