УПП, формирование записей книги продаж: ускоряем заполнение при большом объеме реализаций

28.07.17

База данных - HighLoad оптимизация

В конце апреля 2017 года ко мне обратилась бухгалтер по НДС с жалобой на очень длительное заполнение документа "Формирование записей книги продаж" по реализации. По ее словам, заполнение документа могло продолжаться от 40 минут до часа за месяц... Разбираемся в ситуации.

Итак, дана находящаяся в актуальном состоянии клиент-серверная УПП. Квартальный объем документов реализации у нас приличный, но далеко не рекордный — примерно около 40 тыс. реализаций товаров и услуг, правда, с тенденцией к увеличению. Пришлось открыть конфигуратор и взяться за изучение 1Сного кода. Результатами решил поделиться с сообществом, потому что вполне может быть, что у кого-то возникнет та же проблема либо в УПП, либо в УТ 10, где этот документ устроен аналогично.

Вскрытие показало, что грабли ожидали нас в модуле документа ФормированиеЗаписейКнигиПродаж, а более конкретно - в процедуре РаспределитьОплатыПоДеревуСФ. В данной процедуре выполняется отбор из таблицы РаспределенныеОплаты с помощью построителя запроса. Отбор несложный, но используются операции на больше/меньше:

Отбор = Построитель_РаспределенныеОплаты.Отбор;
Отбор.Добавить("СчетФактура");
Отбор.СчетФактура.Использование = Истина;
Отбор.Добавить("РаспределеннаяОплата");
Отбор.РаспределеннаяОплата.ВидСравнения = ВидСравнения.Больше;
Отбор.РаспределеннаяОплата.Значение = 0;
Отбор.РаспределеннаяОплата.Использование = Истина;

Таблица РаспределенныеОплаты в базах с большим объемом реализаций обычно не совсем мала — в моем случае она имела на март месяц пару десятков тысяч строк. Но главная проблема даже не в этом, а в том, что в дальнейшем этот отбор делается многократно в цикле с большим количеством итераций:

Для каждого СтрокаСФ Из Дерево_НДСНачисленный.Строки Цикл

НаличиеОплатыНеТребуется = (СтрокаСФ.Строки[0].МоментОпределенияНалоговойБазыНДС = МоментОпределения_ПоОтгрузке) Или Дата >= '20080101';
ТаблицаОплат.Очистить();
Отбор = Построитель_РаспределенныеОплаты.Отбор;
Отбор.СчетФактура.Значение = СтрокаСФ.СчетФактура;
Отбор.РаспределеннаяОплата.ВидСравнения = ?(СтрокаСФ.СуммаСНДС>0,ВидСравнения.Больше,ВидСравнения.Меньше);

Построитель_РаспределенныеОплаты.Выполнить();

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

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

Процедура РаспределитьОплатыПоДеревуСФ(Дерево_НДСНачисленный, ТаблицаРезультатов, СписокСчетовФактур, РаспределенныеОплаты, ОтражатьВРеестре = Истина, ОтражатьВидНачисления = Ложь )

НДСНалоговыйПериод = Неопределено;

// Далее используются следующие комментарии
// [-] и дальнейшее комментирование - исходный фрагмент удален
// [+] {...} - новый фрагмент вставлен

// [-] VVP - удаляем подготовку построителя и его отбора
//Построитель_РаспределенныеОплаты = Новый построительЗапроса();
//Построитель_РаспределенныеОплаты.ИсточникДанных = Новый ОписаниеИсточникаДанных(РаспределенныеОплаты);
//
//// Подготовка структуры отбора
//Отбор = Построитель_РаспределенныеОплаты.Отбор;
//Отбор.Добавить("СчетФактура");
//Отбор.СчетФактура.Использование = Истина;
//Отбор.Добавить("РаспределеннаяОплата");
//Отбор.РаспределеннаяОплата.ВидСравнения = ВидСравнения.Больше;
//Отбор.РаспределеннаяОплата.Значение = 0;
//Отбор.РаспределеннаяОплата.Использование = Истина;
//
//Построитель_РаспределенныеОплаты.Порядок.Добавить("ДатаОплаты");

ТаблицаОплат = Новый ТаблицаЗначений();
ТаблицаОплат.Колонки.Добавить("ДокументОплаты");
ТаблицаОплат.Колонки.Добавить("ДатаОплаты",Новый ОписаниеТипов("Дата", , , Новый КвалификаторыДаты(ЧастиДаты.ДатаВремя)));
ТаблицаОплат.Колонки.Добавить("СуммаОплаты",Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15,2)));

// [-] VVP - удаляем ссылку на таблицу источника построителя
//ТаблицаИсточникаПостроителя = Построитель_РаспределенныеОплаты.ИсточникДанных.ИсточникДанных;

// [+] VVP - делаем свою "таблицу источника построителя" и индексируем ее {
ТаблицаИсточникаПостроителя = РаспределенныеОплаты.Скопировать ();
ВыборкаОплат = РаспределенныеОплаты.СкопироватьКолонки ();
ТаблицаИсточникаПостроителя.Индексы.Добавить ("СчетФактура");
// }

МоментОпределения_ПоОтгрузке = Перечисления.МоментыОпределенияНалоговойБазыНДС.ПоОтгрузке;

Для каждого СтрокаСФ Из Дерево_НДСНачисленный.Строки Цикл

ТаблицаОплат.Очистить();

Если УчетНДС.ДляСчетаФактурыНеТребуетсяОплата(СтрокаСФ.СчетФактура) Тогда

НаличиеОплатыНеТребуется = Истина;

Иначе

НаличиеОплатыНеТребуется = (СтрокаСФ.Строки[0].МоментОпределенияНалоговойБазыНДС = МоментОпределения_ПоОтгрузке) Или Дата >= '20080101';

// [-] VVP - удаляем запрос построителем
//Отбор = Построитель_РаспределенныеОплаты.Отбор;
//Отбор.СчетФактура.Значение = СтрокаСФ.СчетФактура;
//Отбор.РаспределеннаяОплата.ВидСравнения = ?(СтрокаСФ.СуммаСНДС>0,ВидСравнения.Больше,ВидСравнения.Меньше);
//
//Построитель_РаспределенныеОплаты.Выполнить();
//Если Построитель_РаспределенныеОплаты.Результат.Пустой() и не НаличиеОплатыНеТребуется и СтрокаСФ.СуммаСНДС >= 0 Тогда
// // Оплата не обнаружена
// Продолжить;
//КонецЕсли;
//
//ВыборкаОплат = Построитель_РаспределенныеОплаты.Результат.Выгрузить(ОбходРезультатаЗапроса.Прямой);

// [+] VVP - делаем свой "запрос" данных через НайтиСтроки и далее навигацией по строкам {

МассивСтрокОплатПоСФ = ТаблицаИсточникаПостроителя.НайтиСтроки (Новый Структура ("СчетФактура", СтрокаСФ.СчетФактура));
ВыборкаОплат.Очистить ();
Для Каждого СтрокаОплатыПоСФ Из МассивСтрокОплатПоСФ Цикл

Если ((СтрокаСФ.СуммаСНДС > 0) И (СтрокаОплатыПоСФ.РаспределеннаяОплата > 0)) или
((СтрокаСФ.СуммаСНДС <= 0) И (СтрокаОплатыПоСФ.РаспределеннаяОплата < 0)) Тогда

СтрокаВыборкиОплат = ВыборкаОплат.Добавить ();

ЗаполнитьЗначенияСвойств(СтрокаВыборкиОплат, СтрокаОплатыПоСФ);

КонецЕсли;

КонецЦикла;

ВыборкаОплат.Сортировать ("ДатаОплаты");

Если ВыборкаОплат.Количество()=0 и не НаличиеОплатыНеТребуется и СтрокаСФ.СуммаСНДС >= 0 Тогда

// Оплата не обнаружена
Продолжить;

КонецЕсли;

// }

СуммаКПогашению = СтрокаСФ.СуммаСНДС;

В 

... и далее код от 1С без изменений.

Добавлю, что индексация таблицы по колонке СчетФактура в данном случае несколько увеличивает скорость поиска, но несущественно, а вот отказ от построителя в пользу метода НайтиСтроки дает огромную прибавку в скорости даже на неиндексированной таблице. В случае с моей УПП скорость выполнения процедуры без индексации таблицы увеличилась примерно в 10 раз — с 40 минут до 4, а с индексацией удалось добиться примерно 3 минут вместо 4. В конечном итоге я все же оставил индексацию таблицы в рабочем коде.

См. также

SALE! 20%

Оптовая торговля Розничная торговля Обмен с ГосИС Бухгалтер Платформа 1С v8.3 1С:Управление торговлей 10 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 Розничная и сетевая торговля (FMCG) Оптовая торговля, дистрибуция, логистика Рестораны, кафе и фаст-фуд Россия Бухгалтерский учет Управленческий учет Акцизы Платные (руб)

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

8970 7176 руб.

15.12.2015    170793    955    364    

400

Производство готовой продукции (работ, услуг) Программист Пользователь Платформа 1С v8.3 Оперативный учет 1С:Управление нашей фирмой 1.6 1С:Управление нашей фирмой 3.0 Управленческий учет Платные (руб)

Разработка “Пульт управления производством для 1С:УНФ” содержит цифровые инструменты и средства для производственного и технологического программного обеспечения автоматизации производства - подсистему Технологического контроля с АРМ Контролёра, Учет рекламации, АРМ Начальника производства, АРМ Рабочего цеха

36000 руб.

22.02.2022    18563    13    2    

23

SALE! 20%

Загрузка и выгрузка в Excel Оптовая торговля Печатные формы Бухгалтер Пользователь Платформа 1С v8.3 Управляемые формы Платформа 1C v8.2 Конфигурации 1cv8 1С:Комплексная автоматизация 1.х 1С:Бухгалтерия 2.0 1С:Управление торговлей 10 1С:Розница 2 1С:Управление производственным предприятием 1С:Управление нашей фирмой 1.6 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Управление холдингом 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 1С:Розница 3.0 Бухгалтерский учет Управленческий учет Платные (руб)

Универсальная обработка для загрузки документов из Excel в 1С одним нажатием. Не требует указания параметров (номера колонок, номер первой строки таблицы и т.д.) и предварительной настройки. Просто выбираете файл Excel, документ 1С и нажимаете кнопку "Загрузить". Обработка сама находит таблицу в файле Excel, необходимые для загрузки данные в ней (номенклатура, количество, НДС, цена, сумма) и загружает ее в 1С. Вместе с номенклатурой может найти контрагента, номер и дату документа, штрих-коды, серии ГТД, страну и т.д. Распознает документы ЛЮБОЙ ФОРМЫ (УПД, ТОРГ-12, заказ, отчет комиссионера и т.д.). Не требует MS Office. Для поиска таблиц используются методы эвристического поиска. Загружает только то, что нужно, т.е. пропускает повторы шапки таблицы, заголовки, промежуточные итоги, подписи и т.д. Содержит модуль работы с электронной почтой и api-загрузчик отчетов о продажах маркетплейсов.

6000 5100 руб.

09.11.2016    234117    1062    898    

1003

SALE! 10%

Перенос данных 1C Взаиморасчеты Оптовая торговля Логистика, склад и ТМЦ Файловый обмен (TXT, XML, DBF), FTP Системный администратор Программист Платформа 1С v8.3 1С:Управление торговлей 10 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Россия Управленческий учет Платные (руб)

Можно проверить до покупки, оставьте заявку! Воспользовались более 268 компаний! Перенос данных из УТ 10.3 в УТ 11 | из УТ 10.3 в КА 2 | из УТ 10.3 в ERP. Предлагаем качественное и проверенное временем решение для перехода с УТ 10.3. Можно перенести начальные остатки, нормативно-справочную информацию и все возможные документы. При выгрузке можно установить отбор по периоду, организациям и складам. При выходе новых релизов конфигураций 1C оперативно выпускаем обновление переноса данных.

55778 50200 руб.

24.04.2015    194950    150    243    

280

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

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

70000 руб.

08.12.2021    26816    25    73    

34

Оптовая торговля Производство готовой продукции (работ, услуг) Розничная торговля Обмен с ГосИС Программист Бухгалтер Пользователь Платформа 1С v8.3 Конфигурации 1cv8 Сельское хозяйство и рыболовство Розничная и сетевая торговля (FMCG) Оптовая торговля, дистрибуция, логистика Рестораны, кафе и фаст-фуд Пищевая промышленность Россия Бухгалтерский учет Управленческий учет Платные (руб)

Универсальная конфигурация Хамелеон Меркурий для взаимодействия с системой Меркурий (тестовый+рабочий+демо контур) может использоваться для интеграции в любую конфигурацию на базе 1С, версии ПРОФ и выше. Основное отличие от других решений - работа через веб-интерфейс и API 2.0(API 2.1). Для удобства реализован общий интерфейс в виде обработки, схожей с интерфейсом Меркурий, но возможностей гораздо больше, т.к. при интеграции в Вашу учетную систему, можно на основании Ваших справочников и документов, создавать соответствующие документы и справочники в системе Меркурий и наоборот.

44000 руб.

08.11.2017    122945    292    140    

398
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. ushakovdv 02.05.17 10:27 Сейчас в теме
Спасибо! 20000 строк заполняет за 16 секунд!
2. spectre1978 61 04.05.17 13:10 Сейчас в теме
(1) Рад, что оказалось полезным.
3. vis_tmp 32 14.05.17 20:11 Сейчас в теме
Зачем разработчики сделали это на построителе?...
4. spectre1978 61 14.05.17 22:47 Сейчас в теме
(3) при наличии сложных условий на построителе код, конечно, красивее и читабельнее. Только скорость оставляет желать сильно много лучшего.
5. Lusha_28 51 26.07.17 08:43 Сейчас в теме
Большое спасибо за вашу статью, очень круто. У нас 40-50 тыс. реализаций и возвратов в месяц, формирование записей книги продаж было -30-40мин., теперь -2-3минуты.
И маленький вопрос:
можно конструкцию
СтрокаВыборкиОплат = ВыборкаОплат.Добавить ();

Для каждого Колонка из ВыборкаОплат.Колонки Цикл

ИндексКолонки = ВыборкаОплат.Колонки.Индекс (Колонка);
СтрокаВыборкиОплат.Установить(ИндексКолонки, СтрокаОплатыПоСФ.Получить (ИндексКолонки));

КонецЦикла;
Показать

заменить на
СтрокаВыборкиОплат = ВыборкаОплат.Добавить ();
ЗаполнитьЗначенияСвойств(СтрокаВыборкиОплат, СтрокаОплатыПоСФ);
?
spectre1978; +1 Ответить
6. spectre1978 61 26.07.17 09:09 Сейчас в теме
(5)да, конечно, и это будет правильно
7. spectre1978 61 28.07.17 08:35 Сейчас в теме
Внес изменение в публикацию в соответствии с заметкой в (5). Спасибо за уточнение!
8. Repey 17.04.20 15:06 Сейчас в теме
Приветствую.

Благодарю, воспользовался решением.
Однако не понятно - для чего тут нужна ТаблицаОплат?
9. spectre1978 61 17.04.20 15:20 Сейчас в теме
(8) Здравствуйте, рад что помогло в работе. По вашему вопросу:
Однако не понятно - для чего тут нужна ТаблицаОплат?

Обратите, пожалуйста, внимание, что в приведенном фрагменте с изменениями цикл верхнего уровня
Для каждого СтрокаСФ Из Дерево_НДСНачисленный.Строки Цикл

и сама процедура
Процедура РаспределитьОплатыПоДеревуСФ(Дерево_НДСНачисленный, ТаблицаРезультатов, СписокСчетовФактур, РаспределенныеОплаты, ОтражатьВРеестре = Истина, ОтражатьВидНачисления = Ложь )

не завершены.
Ниже, уже по коду от 1С из вашего модуля, без моих изменений, данная ТЗ используется.
Оставьте свое сообщение