Имя: Пароль:
1C
1С v8
Как оптимизировать отчет?
,
0 Anabella
 
16.06.15
15:42
Отчет из таблиц SQL выгружает данные в 1с. За месяц отчет выполняется секунд 40. Нужно убыстрить. Есть код формирования скд, есть код выгрузки таблиц из скуля. Что тут можно оптимизировать? Могу скинуть сам отчет, только куда?

&НаСервере
Функция ПолучитьТаблицу()

    Дата1 = Отчет.КомпоновщикНастроек.ПользовательскиеНастройки.Элементы[0].Значение.ДатаНачала;
    Дата2 = Отчет.КомпоновщикНастроек.ПользовательскиеНастройки.Элементы[0].Значение.ДатаОкончания;
    
    ЗапросПродаж = Новый Запрос;
    ЗапросПродаж.УстановитьПараметр("Дата1",Дата1);
    ЗапросПродаж.УстановитьПараметр("Дата2",Дата2);

    ЗапросПродаж.Текст = "ВЫБРАТЬ
            |    OtchetProdazh.Ofis КАК Офисы,
            |    OtchetProdazh.GrupTovara КАК ГруппыТоваров,
            |    OtchetProdazh.KodTovara КАК KodTovara,
            |    СУММА(OtchetProdazh.Vistavleno) КАК Выставлено,
            |    СУММА(OtchetProdazh.Oplacheno) КАК Оплачено,
            |    OtchetProdazh.Data КАК Дата
            |ИЗ
            |    ВнешнийИсточникДанных.OtchetProdazh.Таблица.OtchetProdazh КАК OtchetProdazh
            |ГДЕ
            |    OtchetProdazh.Data >= &Дата1
            |    И OtchetProdazh.Data <= &Дата2 ";

    
    Если Отчет.КомпоновщикНастроек.ПользовательскиеНастройки.Элементы[1].Использование  = Истина
       и Отчет.КомпоновщикНастроек.ПользовательскиеНастройки.Элементы[1].ПравоеЗначение <> 7 тогда
       Офис = ПолучитьОфис();
    ЗапросПродаж.УстановитьПараметр("Ofis","%"+Офис+"%");
       ЗапросПродаж.Текст = ЗапросПродаж.Текст + "И OtchetProdazh.Ofis ПОДОБНО &Ofis ";
   КонецЕсли;
  
   ЗапросПродаж.Текст = ЗапросПродаж.Текст + "СГРУППИРОВАТЬ ПО
            |    OtchetProdazh.Ofis,
            |    OtchetProdazh.GrupTovara,
            |    OtchetProdazh.KodTovara,
            |    OtchetProdazh.Data
            |
            |УПОРЯДОЧИТЬ ПО
            |    KodTovara";
    
    РезультатЗапросаПродаж = ЗапросПродаж.Выполнить().Выгрузить();
    РезультатЗапросаПродаж.Колонки.Добавить("Товары");
    РезультатЗапросаПродаж.Колонки.Добавить("Соотношение");
    //РезультатЗапросаПродаж.Колонки.Добавить("Дата");
    
     кол  = РезультатЗапросаПродаж.Количество();    
    
    строка=0;
    
    Пока строка < кол Цикл
        КодТовара = РезультатЗапросаПродаж[строка].KodTovara;
        Товары = Справочники.Номенклатура.НайтиПоКоду(СокрЛП(КодТовара));
        Пока строка < кол  И КодТовара = РезультатЗапросаПродаж[строка].KodTovara Цикл
            РезультатЗапросаПродаж[строка].Товары = Товары;
            строка = строка+1;
        КонецЦикла;
    КонецЦикла;

    Возврат РезультатЗапросаПродаж;

КонецФункции
1 Волшебник
 
модератор
16.06.15
15:44
Заведи регистр оборотов и сделай агрегат. Отчёт будет формироваться за 1 секунду.
2 Anabella
 
16.06.15
15:46
(1) в рабочую базу вмешиваться очень нежелательно. крайний вариант.
3 MadHead
 
16.06.15
15:50
вообще было бы не плохо увидеть на каких строках сколько тратиться времени. Сразу видно что последний цикл нужно заменить запросом
4 Широкий
 
16.06.15
15:50
(0) Странно, функиця есть "group by" нет
5 MadHead
 
16.06.15
15:51
так же проверить есть ли индекс по датам во внешней базе
6 ДенисЧ
 
16.06.15
15:51
(4)  ЗапросПродаж.Текст = ЗапросПродаж.Текст + "СГРУППИРОВАТЬ ПО
7 Широкий
 
16.06.15
15:52
+4 неполностью посмотрел, сори.

Мне кажется "OtchetProdazh.Data" тут лишняя и с подобно надо что то делать
8 Anabella
 
16.06.15
15:54
(3) 35% времени тратится на строчку     ПроцессорВывода.Вывести(ПроцессорКомпоновки);

26% времени тратится на строчку
    РезультатЗапросаПродаж = ЗапросПродаж.Выполнить().Выгрузить();
9 Широкий
 
16.06.15
15:54
Товары = Справочники.Номенклатура.НайтиПоКоду(СокрЛП(КодТовара));

Это определенно надо в запросе делать
10 Anabella
 
16.06.15
15:57
Охренеть, мне сам Волшебник отвечал! Надо сохранить себе скрин на память :-)
11 Drac0
 
16.06.15
15:58
(0) Запрос с этим условием: "И OtchetProdazh.Ofis ПОДОБНО &Ofis " ?

Ну и (3) с (9) однозначно надо. Если с типами нет косяка.
12 ДенисЧ
 
16.06.15
15:58
(10) теперь неделю глаза не мой ))
13 Anabella
 
16.06.15
15:59
(11) Если стоит отбор по офисам, то добавляется это условие, если нет, то без него. В любом случае неприлично долго.
14 Anabella
 
16.06.15
16:00
(11) касательно (3) я уже ответила в (8) 2 самые долгие позиции. А касательно (9) сейчас переделываю.
15 Anabella
 
16.06.15
16:01
(12) Чуяло мое нутро, не надо было сегодня глаза красить ))
16 Drac0
 
16.06.15
16:05
(13) Поиск по параметру такого вида "%"+Офис+"%" херит все индексы. Если они там вообще есть, конечно же. Желательно искать по полному равенству. Или хотя бы знак % оставить только в конце.
17 rsv
 
16.06.15
16:05
(0) У вас внешний источник.... выгрузка просто из  него данных простым селектом скажем Тор 100 сколько времени ?
18 D_E_S_131
 
16.06.15
16:08
(17) Вообще не плохо бы понимать сколько там данных во "внешнем источнике", а то там может не 100, а 100500 и 40 секунд это нормально для такого объема.
19 rsv
 
16.06.15
16:10
+(17) И мы обсуждаем "неприлично долго" работу внешнего источника ? Или   обработку в цикле  курсора оного с вызовом  НайтиПоКоду ?
20 Anabella
 
16.06.15
16:17
(17)(18) первые 100 выбирает за 7,2 сек. Количество записей в таблице за месяц апрель к примеру - 97776.
21 Anabella
 
16.06.15
16:21
(19)Есть отчет и жалоба на него что он работает долго. Собственно я и думаю как-то его убыстрить. Отчет на двух функциях тормозит, первую я выложила, вот вторая (ссылается на функцию выше).

    Если Отчет.КомпоновщикНастроек.ПользовательскиеНастройки.Элементы[1].ПравоеЗначение = 7 тогда
        Отчет.КомпоновщикНастроек.ПользовательскиеНастройки.Элементы[1].Использование = ложь;
    КонецЕсли;
        
    Результат.Очистить();
    ОтчетОбъект = РеквизитФормыВЗначение("Отчет");    
    Схема = ОтчетОбъект.ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
    Настройки = Схема.НастройкиПоУмолчанию;
    
    КомпоновщикНастроекДанных = Новый КомпоновщикНастроекКомпоновкиДанных;        
    КомпоновщикНастроекДанных.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(Схема));
    КомпоновщикНастроекДанных.ЗагрузитьНастройки(Схема.НастройкиПоУмолчанию);
    КомпоновщикНастроекДанных.ЗагрузитьПользовательскиеНастройки(Отчет.КомпоновщикНастроек.ПользовательскиеНастройки);
    
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    Макет = КомпоновщикМакета.Выполнить(Схема, КомпоновщикНастроекДанных.ПолучитьНастройки());
                
    ТаблицаЗаказов = ПолучитьТаблицу();
        
    ВнешниеНаборыДанных = Новый Структура;  ///присоединяем к скд наш внешний набор данных
    ВнешниеНаборыДанных.Вставить("Результат",ТаблицаЗаказов);
    
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;        
    ПроцессорКомпоновки.Инициализировать(Макет, ВнешниеНаборыДанных);
    
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(Результат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
    Элементы.Результат.ОтображениеСостояния.Видимость = Ложь;
    Элементы.Результат.ОтображениеСостояния.ДополнительныйРежимОтображения = ДополнительныйРежимОтображения.НеИспользовать;
    
    Результат.ПоказатьУровеньГруппировокСтрок(1);
    Результат.ПоказатьУровеньГруппировокСтрок(0);
                     
        Офис = ПолучитьОфис();
        Если Офис = "Общий" тогда
            ТаблицаЗаказов.Свернуть("Офисы,Дата","Оплачено");
            Строка = "[";
            Для каждого СтрТЗ из ТаблицаЗаказов Цикл
                Если СтрТЗ.Офисы<>"" и СтрТЗ.Офисы <> null тогда
                    Строка = Строка + Строка("["+Формат(СтрТЗ.Дата, "ДФ=ггггММдд") + "," + Формат(окр(СтрТЗ.Оплачено,0),"ЧГ=0")+"," + Символ(34)+СтрТЗ.Офисы+Символ(34)+"],");
                КонецЕсли;
            КонецЦикла;
            Строка = Строка+"]";
        Иначе
            ТаблицаЗаказов.Свернуть("ГруппыТоваров,Дата","Оплачено");
            Строка = "[";
            Для каждого СтрТЗ из ТаблицаЗаказов Цикл
                Если СтрТЗ.ГруппыТоваров<>"" и СтрТЗ.ГруппыТоваров <> null тогда
                    Строка = Строка + Строка("["+Формат(СтрТЗ.Дата, "ДФ=ггггММдд") + "," + Формат(окр(СтрТЗ.Оплачено,0),"ЧГ=0")+"," + Символ(34)+СтрТЗ.ГруппыТоваров+Символ(34)+"],");
                КонецЕсли;                    
            КонецЦикла;    
            Строка = Строка+"]";            
        КонецЕсли;    
    
    Возврат Строка;
22 Anabella
 
16.06.15
16:22
(19) некрасиво получилось... лучше так:

&НаСервере
Функция СформироватьКнопкаНаСервере()
    Время = ТекущаяДата();
    
    Если Отчет.КомпоновщикНастроек.ПользовательскиеНастройки.Элементы[1].ПравоеЗначение = 7 тогда
        Отчет.КомпоновщикНастроек.ПользовательскиеНастройки.Элементы[1].Использование = ложь;
    КонецЕсли;
        
    Результат.Очистить();
    ОтчетОбъект = РеквизитФормыВЗначение("Отчет");    
    Схема = ОтчетОбъект.ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
    Настройки = Схема.НастройкиПоУмолчанию;
    
    КомпоновщикНастроекДанных = Новый КомпоновщикНастроекКомпоновкиДанных;        
    КомпоновщикНастроекДанных.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(Схема));
    КомпоновщикНастроекДанных.ЗагрузитьНастройки(Схема.НастройкиПоУмолчанию);
    КомпоновщикНастроекДанных.ЗагрузитьПользовательскиеНастройки(Отчет.КомпоновщикНастроек.ПользовательскиеНастройки);
    
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    Макет = КомпоновщикМакета.Выполнить(Схема, КомпоновщикНастроекДанных.ПолучитьНастройки());
                
    ТаблицаЗаказов = ПолучитьТаблицу();
        
    ВнешниеНаборыДанных = Новый Структура;  ///присоединяем к скд наш внешний набор данных
    ВнешниеНаборыДанных.Вставить("Результат",ТаблицаЗаказов);
    
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;        
    ПроцессорКомпоновки.Инициализировать(Макет, ВнешниеНаборыДанных);
    
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(Результат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
    Элементы.Результат.ОтображениеСостояния.Видимость = Ложь;
    Элементы.Результат.ОтображениеСостояния.ДополнительныйРежимОтображения = ДополнительныйРежимОтображения.НеИспользовать;
    
    Результат.ПоказатьУровеньГруппировокСтрок(1);
    Результат.ПоказатьУровеньГруппировокСтрок(0);
                     
        Офис = ПолучитьОфис();
        Если Офис = "Общий" тогда
            ТаблицаЗаказов.Свернуть("Офисы,Дата","Оплачено");
            Строка = "[";
            Для каждого СтрТЗ из ТаблицаЗаказов Цикл
                Если СтрТЗ.Офисы<>"" и СтрТЗ.Офисы <> null тогда
                    Строка = Строка + Строка("["+Формат(СтрТЗ.Дата, "ДФ=ггггММдд") + "," + Формат(окр(СтрТЗ.Оплачено,0),"ЧГ=0")+"," + Символ(34)+СтрТЗ.Офисы+Символ(34)+"],");
                КонецЕсли;
            КонецЦикла;
            Строка = Строка+"]";
        Иначе
            ТаблицаЗаказов.Свернуть("ГруппыТоваров,Дата","Оплачено");
            Строка = "[";
            Для каждого СтрТЗ из ТаблицаЗаказов Цикл
                Если СтрТЗ.ГруппыТоваров<>"" и СтрТЗ.ГруппыТоваров <> null тогда
                    Строка = Строка + Строка("["+Формат(СтрТЗ.Дата, "ДФ=ггггММдд") + "," + Формат(окр(СтрТЗ.Оплачено,0),"ЧГ=0")+"," + Символ(34)+СтрТЗ.ГруппыТоваров+Символ(34)+"],");
                КонецЕсли;                    
            КонецЦикла;    
            Строка = Строка+"]";            
        КонецЕсли;    
    
    Возврат Строка;    

КонецФункции
23 Гёдза
 
16.06.15
16:23
какая строчка выполняется дольше всего?
24 Anabella
 
16.06.15
16:24
(23)
35% времени тратится на строчку    
ПроцессорВывода.Вывести(ПроцессорКомпоновки);

26% времени тратится на строчку
    РезультатЗапросаПродаж = ЗапросПродаж.Выполнить().Выгрузить();
25 Гёдза
 
16.06.15
16:26
(24) сколько в итоговом отчете строк?
26 Anabella
 
16.06.15
16:27
(9) переделала, стало дольше.

    Пока строка < кол Цикл
        КодТовара = РезультатЗапросаПродаж[строка].KodTovara;
    
    ЗапросТовар = Новый Запрос;
    ЗапросТовар.Текст = "ВЫБРАТЬ
                        |    Номенклатура.Ссылка
                        |ИЗ
                        |    Справочник.Номенклатура КАК Номенклатура
                        |ГДЕ
                        |    Номенклатура.Код = &Код";
    ЗапросТовар.УстановитьПараметр("Код",КодТовара);
    ВыборкаТовар = ЗапросТовар.Выполнить().Выбрать();
    ВыборкаТовар.Следующий();
    РезультатЗапросаПродаж[строка].Товары = ВыборкаТовар.Ссылка;
    строка = строка+1;
    КонецЦикла;
27 Anabella
 
16.06.15
16:28
(25)Количество записей в таблице за месяц апрель к примеру - 97776.
28 Anabella
 
16.06.15
16:35
(25)а вот выгружать из внешних источников в эксель чтобы быстренько глянуть общее количество данных явно не стоило... сижу, жду, когда отвиснет.
29 Широкий
 
16.06.15
16:37
(26) Ну ты конечно переделала :)
30 Зеленый пень
 
16.06.15
16:38
Сначал собрать все коды товаров в массив, потом сделать запрос по товарам с этим кодов - выгрузить в ТЗ (добавить ТЗ индекс по полю кода).
И в цикле искать уже по коду в ТЗ, а не делать запрос по каждой строке.
31 Anabella
 
16.06.15
16:38
(29)Я старалась, спешила, пока желающие помочь не пропали) Что исправить?
32 Anabella
 
16.06.15
16:39
(30)Спасибо!
33 Широкий
 
16.06.15
16:39
(32) Не надо его благодарить - он гадость советует
34 Anabella
 
16.06.15
16:40
(33)Спасибо отменяется, кто чего хорошего посоветует?)
35 Широкий
 
16.06.15
16:40
(32) У тебя уже есть запрос из внешнего источника - в нем же через левое соединение получи номенклатуру
36 Anabella
 
16.06.15
16:42
(35)Гениально, черт побери
37 Anabella
 
16.06.15
16:45
(35)использование нескольких источников данных недопустимо, пишет (
38 Drac0
 
16.06.15
16:51
(37) Выбери сначала в ВТ из внешнего. Потом к этой ВТ уже присоединяй.
39 Anabella
 
16.06.15
16:53
(38)Ща, спасибо!
40 Anabella
 
16.06.15
17:00
(38)Та же ошибка при попытке создания временной таблицы из внешнего источника данных( Получение данных из нескольких источников недопустимо (
41 Drac0
 
16.06.15
17:10
(40) Кажется, я вспомнил, почему мы не юзаем внешние источники данных -_-

Тогда (30). Верни ему спасибо :)
42 Anabella
 
16.06.15
17:16
(30) Спасибо! :-)
43 Широкий
 
17.06.15
09:31
(42) Выгрузи тогда первый запрос в таблицу значений и прогрузи ее во времянку а там левое соединение.
44 Anabella
 
19.06.15
11:41
(43)по скорости получилось примерно одинаково, но метод по (30) сработал чуть быстрее.
45 WebberNSK
 
19.06.15
12:23
(0)  а вот это что такое? Офис = ПолучитьОфис();