Решение проблемы ПроверитьВывод() для огромных документов

06.11.17

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

Пример того, как я ускорил вывод большого табличного документа(100+ страниц)

Скачать файлы

Наименование Файл Версия Размер
Инвентаризационная опись в разрезе головных изделий
.epf 33,91Kb
3
.epf 33,91Kb 3 Скачать

Каких результатов удалось достичь

Изначально, печатная форма, содержащая ~200 страниц выводилась(речь идет об именно выводе в табличный документ) > 15 минут. В результате оптимизации удалось сократить время до 1-2 минут.

Последовательность действий:

  1. Объявляем ТабличныйДокумент как ранее, настраиваем его свойства(Масштаб, ориентация страницы, поля);
  2. Объявляем еще один табличный документ, назовем его ИтоговыйТабличныйДокумент, копируем в него все свойства ранее созданного;
  3. Выполняем вывод одной страницы в ТабличныйДокумент, проверяем, умещается ли он или нет с помощью метода ПроверитьВывод()
  4. Когда вывод не умещается на странице ТабличныйДокумент, то:
    1. Выполняем его вывод в ИтоговыйТабличныйДокумент методом Вывести(ТабличныйДокумент)
    2. Очищаем ТабличныйДокумент
    3. Выводим шапку(если требуется) в Табличный документ
  5. Пункты 3-4 повторяются в цикле, как и при обычном формировании печатных форм
  6. В конце формирования выводим подвал в ИтоговыйТабличныйДокумент

Как это выглядит в программе

    ТабДокумент = Новый ТабличныйДокумент;
    ТабДокумент.ИмяПараметровПечати = "ПАРАМЕТРЫ_ПЕЧАТИ_ИнвентаризационнаяОписьВРазрезеГоловныхИзделий";
    ТабДокумент.ОриентацияСтраницы  = ОриентацияСтраницы.Портрет;
    ТабДокумент.МасштабПечати = 90;
    Макет   = ПолучитьМакет("ИнвентаризационнаяОпись");
    
    // Документ используется для вывода по страницам
    ИтоговыйТабДок = Новый ТабличныйДокумент;
    ЗаполнитьЗначенияСвойств(ИтоговыйТабДок, ТабДокумент); 
    
    НомерСтрокиНачало = ТабДокумент.ВысотаТаблицы + 1;
    Запрос = Новый Запрос;
    Запрос.Текст=
    "ВЫБРАТЬ
    |    ИнвентаризацияНЗП.Организация,
    |    ИнвентаризацияНЗП.Подразделение,
    |    ИнвентаризацияНЗП.Ссылка,
    |    ИнвентаризацияНЗП.Номер,
    |    ИнвентаризацияНЗП.Дата,
    |    ИнвентаризацияНЗП.Заказ,
    |    ИнвентаризацияНЗП.ВводитьЗаказыПоСтрокам,
    |    ИнвентаризацияНЗП.Заказ.Представление КАК ЗаказПредставление,
    |    ИнвентаризацияНЗП.Организация.Представление КАК ОрганизацияПредставление,
    |    ИнвентаризацияНЗП.Подразделение.Представление КАК ПодразделениеПредставление
    |ИЗ
    |    Документ.ИнвентаризацияНЗП КАК ИнвентаризацияНЗП
    |ГДЕ
    |    ИнвентаризацияНЗП.Ссылка = &ТекДок";
    Запрос.УстановитьПараметр("ТекДок", СсылкаНаОбъект);
    
    Шапка = Запрос.Выполнить().Выбрать();
    Шапка.Следующий();
    
    ИнфоОрг = УправлениеКонтактнойИнформацией.СведенияОЮрФизЛице(Шапка.Организация, СсылкаНаОбъект.Дата);
    
    Область = Макет.ПолучитьОбласть("Шапка");
    Область.Параметры.ПечНомерДок      = Шапка.Номер;
    Область.Параметры.ПечДатаДок       = Шапка.Дата;
    Область.Параметры.ПечОрганизация   = ИнфоОрг.ПолноеНаименование;
    Область.Параметры.ПечПодразделение = Шапка.ПодразделениеПредставление;
    
    Область.Параметры.КодОКПО          = ИнфоОрг.КодПоОКПО;
    Область.Параметры.Организация      = Шапка.Организация;
    Область.Параметры.Подразделение    = Шапка.Подразделение;
    
    ТабДокумент.Вывести(Область);
    ОбластьТабШапка = Макет.ПолучитьОбласть("ТабШапка");
    ТабДокумент.Вывести(ОбластьТабШапка);
    
    Индекс       = 0;
    ВсегоТМЦ     = 0;
    ВсегоКолФакт = 0;
    ВсегоКолОПУ  = 0;
    ВсегоКолОтк  = 0;
    КолФактСтр   = 0;
    СтрокНаЛисте = 5;// Изменим, подбирается опытным путем
    НПП = 0;
    ВсегоСтраниц = 0;    
    
    
    ВсегоИзделий = ДанныеДляПечати.Строки.Количество();
    
    ОбластьПодвал = Макет.ПолучитьОбласть("ПодвалСтраницы");
    
    Для Каждого СтрокаДЗ1 Из ДанныеДляПечати.Строки Цикл
        
        Состояние("Производится вывод печатной формы (изделие "+ (ДанныеДляПечати.Строки.Индекс(СтрокаДЗ1) + 1) + "/" + ВсегоИзделий + "). Стр. " + ВсегоСтраниц);
        
        Область  = Макет.ПолучитьОбласть("СтрокаПродукция");
        Область.Параметры.ПечНоменклатура = СтрокаДЗ1.НоменклатураПредставление;
        Область.Параметры.Номенклатура    = СтрокаДЗ1.Номенклатура;
        Область.Параметры.ПечКолБух          = Формат(СтрокаДЗ1.Количество, "ЧЦ=15; ЧДЦ=3");
        Область.Параметры.ПереченьЗаказов = СтрокаДЗ1.ПереченьЗаказов;
        ТабДокумент.Вывести(Область);
        
        Для Каждого СтрокаДЗ2 Из СтрокаДЗ1.Строки Цикл
            
            // Делаем через проверить вывод
            Индекс   = Индекс + 1;
            ВсегоТМЦ = ВсегоТМЦ + 1;
            НПП      = НПП + 1;
            Область  = Макет.ПолучитьОбласть("Строка");
            Область.Параметры.ПечНомер        = Формат( НПП, "ЧЦ=6; ЧН=");
            Область.Параметры.ПечНоменклатура = СтрокаДЗ2.НоменклатураПредставление;
            Область.Параметры.Номенклатура    = СтрокаДЗ2.Номенклатура;
              
            
            //Область.Параметры.ПечШифрИВЦ      = Шифр;
            Область.Параметры.ПечКодТМЦ       = СокрЛП(СтрокаДЗ2.НоменклатураКод);
            Область.Параметры.ПечКодЕИ        = СтрокаДЗ2.ЕдиницаИзмеренияКод;
            Область.Параметры.ПечЕИ           = СтрокаДЗ2.ЕдиницаИзмерения;
            
            Область.Параметры.ПечКолБух       = Формат(СтрокаДЗ2.Количество, "ЧЦ=15; ЧДЦ=3");
            
            // Если с подвалом не умещается - выводим подвал, начинаем новую страницу
            МассивДляПроверки = Новый Массив;
            МассивДляПроверки.Добавить(Область);
            //МассивДляПроверки.Добавить(ОбластьПодвал);
            Если ТабДокумент.ПроверитьВывод(МассивДляПроверки) = ЛОЖЬ Тогда
                
                // Подвал страницы просили не выводить
                //ОбластьПодвал.Параметры.КолНомСтр  = Индекс;
                //ОбластьПодвал.Параметры.ИтогКолСтр = КолФактСтр;
                //ТабДокумент.Вывести( ОбластьПодвал);
                Индекс     = 0;
                КолФактСтр = 0;
                ТабДокумент.ВывестиГоризонтальныйРазделительСтраниц();
                СтрокНаЛисте = 10; // Изменено - подбирается опытным путем  Это было раньше (На первом листе 9 строк, на остальных 30)
                
                ВсегоСтраниц = ВсегоСтраниц + 1;
                
                // Переносим изменения в итоговый документ, очищаем оригинал, выводим шапку на след.странице
                ИтоговыйТабДок.Вывести(ТабДокумент);
                
                ТабДокумент.Очистить();
                ТабДокумент.Вывести(ОбластьТабШапка);
                
            КонецЕсли;

            ОбработкаПрерыванияПользователя();// На всякий случай
            
            ТабДокумент.Вывести(Область);
            
            КолФактСтр   = КолФактСтр   + СтрокаДЗ2.Количество;
            ВсегоКолФакт = ВсегоКолФакт + СтрокаДЗ2.Количество;

        КонецЦикла;
        
    КонецЦикла;
    
    Область = Макет.ПолучитьОбласть("Итого");
    Область.Параметры.ПечКолФактИтого = Формат( ВсегоКолФакт, "ЧЦ=15; ЧДЦ=3");
    
    // Подвал страницы просили не выводить
    //ТабДокумент.Вывести( Область);
    //Если Индекс > 0 Тогда
    //    ОбластьПодвал = Макет.ПолучитьОбласть("ПодвалСтраницы");
    //    ОбластьПодвал.Параметры.КолНомСтр  = Индекс;
    //    ОбластьПодвал.Параметры.ИтогКолСтр = КолФактСтр;
    //    ТабДокумент.Вывести( ОбластьПодвал);
    //КонецЕсли;
    
    Область = Макет.ПолучитьОбласть("Подвал");
    Область.Параметры.ВсегоТМЦ      = ВсегоТМЦ;
    Область.Параметры.ИтогоКолОпись = ВсегоКолФакт;
    ТабДокумент.ВывестиГоризонтальныйРазделительСтраниц();
    ТабДокумент.Вывести( Область);
    //УправлениеПечатью.ЗадатьОбластьПечатиДокумента(ТабДокумент, НомерСтрокиНачало, Новый СписокЗначений, СсылкаНаОбъект);
    
    // Выведем всяческие подвалы
    ИтоговыйТабДок.Вывести(ТабДокумент);

Бонусом идет печатная форма для УПП 1.3, в которой присутствует этот кусок кода

См. также

Оптимизация нагрузки на ЦП сервера СУБД используя типовые индексы

HighLoad оптимизация Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Анализ простого плана запроса. Оптимизация нагрузки на ЦП сервера СУБД используя типовые индексы.

13.03.2024    2429    spyke    26    

39

Анализируем SQL сервер глазами 1С-ника

HighLoad оптимизация Инструменты администратора БД Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

Обработка для простого и удобного анализа настроек, нагрузки и проблем с SQL сервером с упором на использование оного для 1С. Анализ текущих зааросов на sql, ожиданий, конвертация запроса в 1с и рекомендации где может тормозить

1 стартмани

15.02.2024    7360    149    ZAOSTG    66    

95

Удаление строк из таблицы значений различными способами с замером производительности

HighLoad оптимизация Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

Встал вопрос: как быстро удалить строки из ТЗ? Рассмотрел пять вариантов реализации этой задачи. Сравнил их друг с другом на разных объёмах данных с разным процентом удаляемых строк. Также сравнил с выгрузкой с отбором по структуре.

09.01.2024    5769    doom2good    48    

63

Опыт оптимизации 1С на PostgreSQL

HighLoad оптимизация Бесплатно (free)

При переводе типовой конфигурации 1C ERP/УТ/КА на PostgreSQL придется вложить ресурсы в доработку и оптимизацию запросов. Расскажем, на что обратить внимание при потерях производительности и какие инструменты/подходы помогут расследовать проблемы после перехода.

20.11.2023    8594    ivanov660    6    

75

ТОП проблем/задач у владельцев КОРП лицензий 1С на основе опыта РКЛ

HighLoad оптимизация Бесплатно (free)

Казалось бы, КОРП-системы должны быть устойчивы, быстры и надёжны. Но, работая в рамках РКЛ, мы видим немного другую картину. Об основных болевых точках КОРП-систем и подходах к их решению пойдет речь в статье.

15.11.2023    4999    a.doroshkevich    20    

72

Начните уже использовать хранилище запросов

HighLoad оптимизация Запросы

Очень немногие из тех, кто занимается поддержкой MS SQL, работают с хранилищем запросов. А ведь хранилище запросов – это очень удобный, мощный и, главное, бесплатный инструмент, позволяющий быстро найти и локализовать проблему производительности и потребления ресурсов запросами. В статье расскажем о том, как использовать хранилище запросов в MS SQL и какие плюсы и минусы у него есть.

11.10.2023    15964    skovpin_sa    14    

98

Как эффективно настроить autovacuum в Postgres для 1С

HighLoad оптимизация Администрирование СУБД Платформа 1С v8.3 Бесплатно (free)

Кто не любит убирать мусор? Думаю, практически все, а вот в Postgres это обязательный ритуал для эффективной работы. Как эффективно настроить уборку за 1С в Postgres, можно прочитать в этой статье и еще раз задуматься о бесплатности Postgres.

05.08.2023    4976    1CUnlimited    5    

51
Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. Armando 1399 06.11.17 22:43 Сейчас в теме
На 8.3.11 не проверяли? Там что-то оптимизировали на эту тему:

Оптимизирована работа метода табличного документа ПроверитьВывод().
Источник: http://downloads.v8.1c.ru/content//Platform/8_3_11_2700/V8Update.htm#0bacf61e-057e-11e7-a3f7-0050569f678a
SITR-utyos; +1 Ответить
2. SITR-utyos 1419 07.11.17 07:08 Сейчас в теме
(1) Нет, на 8.3.11 не проверял. Последняя платформа, что у меня стоит 8.3.10.2639 - там такая же проблема.
Спасибо, за заметку
3. mifka186 8 07.11.17 09:41 Сейчас в теме
Что-то подобное в расчетном листке организации ЗУП 2.5 используется.

Если ВыводитьПоСтраницам Тогда
			
	ОбластьПриемник = ТабличныйДокументДляПроверки.Область(ТабличныйДокументДляПроверки.ВысотаТаблицы + 1, ,ТабличныйДокументДляПроверки.ВысотаТаблицы + (НомерСтрокиКонцаРЛ - НомерСтрокиНачалаРЛ) + 1, );
	ТабличныйДокументДляПроверки.ВставитьОбласть(ОбластьРЛ, ОбластьПриемник, , истина);
		
	КоличествоСтраниц = 0;
	Попытка
		КоличествоСтраниц = ТабличныйДокументДляПроверки.КоличествоСтраниц();
	Исключение
	КонецПопытки;
			
	Если КоличествоСтраниц > 1 тогда
				
		ТабличныйДокумент.Область(НомерСтрокиНачалаРЛ, , НомерСтрокиНачалаРЛ,).НачалоСтраницы = истина;
				
		ТабличныйДокументДляПроверки.Очистить();
			
		Для сч = 0 по НастройкаШириныКолонокРасчетногоЛистка.ВГраница() Цикл
			ОбластьКолонкиРЛ                  = ТабличныйДокументДляПроверки.Область(, сч+1, , сч+1);
			ОбластьКолонкиРЛ.ШиринаКолонки    = НастройкаШириныКолонокРасчетногоЛистка[сч];
			ОбластьКолонкиРЛ.РазмещениеТекста = ПолучитьТипРазмещенияТекста(НастройкаРазмТекстаКолонокРасчетногоЛистка[сч]);
		КонецЦикла;
				
		ОбластьПриемник = ТабличныйДокументДляПроверки.Область(ТабличныйДокументДляПроверки.ВысотаТаблицы + 1, ,ТабличныйДокументДляПроверки.ВысотаТаблицы + (НомерСтрокиКонцаРЛ - НомерСтрокиНачалаРЛ) + 1, );
		ТабличныйДокументДляПроверки.ВставитьОбласть(ОбластьРЛ, ОбластьПриемник, , истина);
				
	КонецЕсли;
			
КонецЕсли;
Показать
4. madonov 169 07.11.17 09:49 Сейчас в теме
Плюс за идею. Взял на вооружение.
5. nvv1970 07.11.17 11:14 Сейчас в теме
Работа с табличным документом, текстовым документом деградирует пропорционально росту его объема. Поэтому можно применять не только указанный метод, но и использовать для организации печати страниц двумерный массив табличных документов. Так можно определить последовательность вывода по строкам, столбам, чёт/нечет и т.д. на сколько хватит фантазии.
sm.artem; +1 Ответить
6. BigB 191 07.11.17 12:09 Сейчас в теме
Каждый месяц генерирую примерно > 600 тысяч квитанций пачками по 1000 листов в пачке.
На каждой странице (внизу) есть адрес доставки и кому.
Квитанция должна занимать не более одной страницы.
Я поступаю так: если адрес доставки больше 150 тогда делаю проверку на количество страниц и если произошел перенос адреса на другую страницу - уменьшаю шрифт, пока не влезет в одну страницу.
Вот такой кусок кода у меня:
//Автоматическое изменение размера шрифта адреса доставки
Если СтрДлина(Выборка.АдресДоставки)>150 И ТДП.КоличествоСтраниц()>ХХ Тогда
	Y=Формат(ТДП.Области.Подвал.Низ,"ЧГ=0");
	ОбластьДоставки=ТДП.Область("R"+Y+"C2:R"+Y+"C10");
	Пока Истина Цикл
		ОбластьДоставки.Шрифт=Новый Шрифт(ОбластьДоставки.Шрифт,ОбластьДоставки.Шрифт.Имя,ОбластьДоставки.Шрифт.Размер-1);
		Если ТДП.КоличествоСтраниц()=ХХ Тогда
			Прервать
		ИначеЕсли ОбластьДоставки.Шрифт.Размер<7 Тогда
			Сообщить("Л/С "+Выборка.НомерЛС+" Не удалось разместить на одной странице адрес доставки:"+Символы.ПС+Выборка.АдресДоставки);
			Прервать
		КонецЕсли;
	КонецЦикла;
КонецЕсли;
Показать
cargobird; jaroslav.h; sm.artem; AlexGroovy; Danil.Potapov; +5 Ответить
7. vis_tmp 32 08.11.17 06:33 Сейчас в теме
Спасибо, интересный метод ускорения печати больших отчётов!
8. AlexGroovy 08.11.17 11:11 Сейчас в теме
А где именно в коде оптимизация ? Я понял,если бы вы избежали ПроверитьВывод(),но у он у вас остался и находится в цикле.Смысл в том,что всё выводится в итоговый табличный документ?
9. корум 287 08.11.17 11:52 Сейчас в теме
(8)
А где именно в коде оптимизация ? Я понял,если бы вы избежали ПроверитьВывод(),но у он у вас остался и находится в цикле.Смысл в том,что всё выводится в итоговый табличный документ?

нет, не понял.
Смысл в том, что не тормозит.
ПроверитьВывод() 3 страниц 0,01 сек, ПроверитьВывод() 300 страниц не 1 сек, а 100.
ПроверитьВывод() для 3 страниц 100 раз - 1 сек.
user717534; madonov; +2 Ответить
11. AlexGroovy 08.11.17 14:13 Сейчас в теме
А как у вас получается область на 300 страниц сразу,если вы в цикле как и в типовом механизме добавляете по области строчке и сразу переносите другие на новую страницу?
13. madonov 169 09.11.17 02:36 Сейчас в теме
(11) да не область на 300 страниц. А сам табличный документ на 300 страниц.

БольшойТабличныйДокумент.ПроверитьВывод(Область)
работает гозадо медленнее чем
МалыйТабличныйДокумент.ПроверитьВывод(Область)

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

Ускорение происходит не за счет того, что уменьшается количество вызовов функции ПроверитьВывод(), а за счет того, что каждый вызов занимает в разы меньше времени.
OksanaVl; starik-2005; echo77; klinval; корум; AlexGroovy; +6 Ответить
14. AlexGroovy 09.11.17 09:54 Сейчас в теме
(13)Спасибо большое за ответ =)
10. BigB 191 08.11.17 12:35 Сейчас в теме
(0) Уберите из названия "для огромных документов".
Поверьте мне - 200 страниц это мизерный документ.
Не используйте ПроверитьВывод().
Вместо этого используйте КоличествоСтраниц() в разумных пределах и отчет будет формироваться очень быстро.
12. madonov 169 09.11.17 02:28 Сейчас в теме
(10) предположим, что выводим область и при помощи КоличествоСтраниц() видим, что количество страниц увеличилось.
И как без ПроверитьВывод() определить целиком ли новая новая область на новой странице или её "разорвало" на разные и требуется вставка разрыва страницы?
15. zhuravlev_as 392 09.11.17 09:59 Сейчас в теме
Идея интересная. Надо запомнить
16. androgin 10.11.17 00:55 Сейчас в теме
Простите, а если длина наименования постоянно разная и может занимать 1,2,3 строки, то как вы это обойдете?
На одном листе может быть 40 строк, а следующем 50, а третьем ваще 35.
Тут уже параметр СтрокНаЛисте не имеет смысла
17. echo77 1868 10.11.17 05:59 Сейчас в теме
(16) В примере переменная СтрокНаЛисте нигде не используется, если посмотреть циклы внимательное. Это наследие типовой формы инвентаризации - там сделано именно так
Оставьте свое сообщение