Имя: Пароль:
1C
1С v8
Как ускорить выполнение запроса?
0 ColonelAp4u
 
24.06.15
16:13
Добрый день! Есть обработка которая из заявок на расходование средств создает платежные поручения исходящие. При создании платежки в запросе перебираю каждую строку из заявки и проверяю если по данному документу была полная оплата то не переношу это строку в платежку!
Вот Код запроса и добавления платежки
Запрос = Новый Запрос;
                        Запрос.Текст = "ВЫБРАТЬ
                        |    ВложенныйЗапрос.Остаток
                        |ИЗ
                        |    (ВЫБРАТЬ
                        |        -ВзаиморасчетыСКонтрагентамиПоДокументамРасчетовОстатки.СуммаВзаиморасчетовОстаток КАК Остаток
                        |    ИЗ
                        |        РегистрНакопления.ВзаиморасчетыСКонтрагентамиПоДокументамРасчетов.Остатки(
                        |                &Дата,
                        |                Контрагент = &Контрагент
                        |                    И ДоговорКонтрагента = &ДоговорКонтрагента
                        |                    И ДокументРасчетовСКонтрагентом = &ДокументРасчетовСКонтрагентом) КАК ВзаиморасчетыСКонтрагентамиПоДокументамРасчетовОстатки) КАК ВложенныйЗапрос";
                        Запрос.УстановитьПараметр("Дата", ТекущаяДата());
                        Запрос.УстановитьПараметр("ДоговорКонтрагента", Стр.ДоговорКонтрагента);
                        Запрос.УстановитьПараметр("Контрагент", Док.Контрагент);
                        Запрос.УстановитьПараметр("ДокументРасчетовСКонтрагентом", стр.ДокументРасчетовСКонтрагентом);                
                        Результат = Запрос.Выполнить();
                        ВыборкаЗапроса = Результат.Выбрать();
                        Если Не ВыборкаЗапроса.Следующий() Тогда
                            НайденныеСтроки.Удалить(Сч);                    
                        Иначе
                            Сч = Сч + 1;
                            Если Зая<> Стр.ЗаявкаНаРасходование Тогда                    
                                ТекЗаявка=ЗаявкиНаРасходованиеСредств.Найти(Стр.ЗаявкаНаРасходование, "Заявка");                
                                Оплатить=ТекЗаявка.Оплатить;
                            КонецЕсли;    
                            
                            Если Оплатить=0 Тогда
                                Продолжить;
                            КонецЕсли;
                            
                            СтрокаПлатеж=Док.РасшифровкаПлатежа.Добавить();
                            Если Оплатить >=ВыборкаЗапроса.Остаток Тогда
                                СтрокаПлатеж.СуммаВзаиморасчетов=ВыборкаЗапроса.Остаток;
                                СтрокаПлатеж.СуммаПлатежа =ВыборкаЗапроса.Остаток;
                                Оплатить=Оплатить-СтрокаПлатеж.СуммаПлатежа;
                            Иначе    
                                СтрокаПлатеж.СуммаВзаиморасчетов=Оплатить;
                                СтрокаПлатеж.СуммаПлатежа = Оплатить;
                                Оплатить=0;
                            КонецЕсли;    
                            
                            СтрокаПлатеж.КурсВзаиморасчетов      = Док.КурсДокумента;
                            СтрокаПлатеж.КратностьВзаиморасчетов = Док.КратностьДокумента;
                            СтрокаПлатеж.СтавкаНДС                         = Док.Контрагент.ОсновнойНДС;
                            СтрокаПлатеж.Сделка                             = Стр.Сделка;
                            СтрокаПлатеж.ДокументРасчетовСКонтрагентом     = Стр.ДокументРасчетовСКонтрагентом;
                            СтрокаПлатеж.ДоговорКонтрагента                 = Стр.ДоговорКонтрагента;
                            Попытка
                                
                                Если ЗначениеЗаполнено(Стр.Сделка) И ТипЗнч(Стр.Сделка) = Тип("ДокументСсылка.ЗаказПоставщику") И Не ЗначениеЗаполнено(Стр.ДокументРасчетовСКонтрагентом) Тогда
                                    
                                    Док.ДатаРасчетов = Стр.Сделка.ДатаПоступления;
                                    
                                Иначе
                                    
                                    ДатаРасчетовНовая = Основание.Дата;
                                    Если ДатаРасчетовНовая = Неопределено Тогда
                                        ДатаРасчетовНовая = ТекущаяДата();
                                    КонецЕсли;    
                                    Док.ДатаРасчетов=ДатаРасчетовНовая;
                                    
                                КонецЕсли;
                                
                                Если ЗначениеЗаполнено(Стр.ДокументРасчетовСКонтрагентом) И ТипЗнч(Стр.ДокументРасчетовСКонтрагентом) = Тип("ДокументСсылка.ПоступлениеТоваровУслуг") Тогда
                                    
                                    Док.ДатаРасчетов = Стр.ДокументРасчетовСКонтрагентом.Дата;    
                                    
                                КонецЕсли;
                                
                            Исключение
                                
                            КонецПопытки;
                            
                            УправлениеДенежнымиСредствами.ПересчитатьСуммуНДС(СтрокаПлатеж);
                            
                            СтрокаПлатеж.СтатьяДвиженияДенежныхСредств     = Стр.СтатьяДвиженияДенежныхСредств;
                            СтрокаПлатеж.Проект                             = Стр.Проект;
                            СтрокаПлатеж.ДокументПланированияПлатежа     = Стр.ЗаявкаНаРасходование;
                            СтрокаПлатеж.КурсВзаиморасчетовПлан             = СтрокаПлатеж.КурсВзаиморасчетов;
                            СтрокаПлатеж.СуммаПлатежаПлан                 = СтрокаПлатеж.СуммаПлатежа;    
                            
                            Зая =Стр.ЗаявкаНаРасходование;

                        КонецЕсли;
1 ColonelAp4u
 
24.06.15
16:14
Пока происходит перебор строк то время уходит не маленькое особенно когда заявок очень много!
2 Господин ПЖ
 
24.06.15
16:14
запрос в цикле
3 Ненавижу 1С
 
гуру
24.06.15
16:16
вижу оператор Продолжить, но не вижу цикла - значит всё вот это во внешнем цикле
а за запрос в цикле рогами об забор

и да - непонятен смысл вложенного подзапроса
4 ХардHard
 
24.06.15
16:18
Запрос.УстановитьПараметр("ДокументРасчетовСКонтрагентом", стр.ДокументРасчетовСКонтрагентом);
(3)  Это и есть в цикле %)
5 ColonelAp4u
 
24.06.15
16:23
(4) Все верно запрос в цикле т.к. мне нужно каждую строку из заявки проверить на была ли оплата или нет, я знаю что в цикле поэтому долго вот и задал вопрос как можно ускорить? выгрузить все строки из заявки во временную табл и потом каждую проверять? но это опять цикл
6 РазДва
 
24.06.15
16:23
(0) Это, кстати, ещё парочка запросов в цикле, которые к тому же получают избыточные данные:
Стр.Сделка.ДатаПоступления
Стр.ДокументРасчетовСКонтрагентом.Дата
7 ColonelAp4u
 
24.06.15
16:25
Цикл такой
сч = 0;
Пока Сч < НайденныеСтроки.Количество() Цикл
Стр = НайденныеСтроки.Получить(Сч);
Потом мой запрос с кодом добавления и
КонецЦикла
8 Господин ПЖ
 
24.06.15
16:27
>Стр.Сделка.ДатаПоступления

за это тоже лупить надо... особенно если поле составного типа
9 VikingKosmo
 
24.06.15
16:28
написать запрос, который проверяет все необходимое не предлагать?
10 ColonelAp4u
 
24.06.15
16:29
(8) это не мой кусок кода, я лишь дописал запрос который будет удалять строки или добавлять
11 ColonelAp4u
 
24.06.15
16:30
(9) предложи я не просто так сюда обратился, любое предложение для меня помощь
12 РазДва
 
24.06.15
16:30
(8) Составной тип тут "рояли" не сыграет, это же не запрос, тип ссылки уже известен, просто будет "считан" весь объект по ссылке в память.
13 Ненавижу 1С
 
гуру
24.06.15
16:31
(10) выкинт и перепиши
14 ColonelAp4u
 
24.06.15
16:32
раньше было вот так
Для каждого Стр из НайденныеСтроки Цикл                            
            Если Зая<> Стр.ЗаявкаНаРасходование Тогда                    
                ТекЗаявка=ЗаявкиНаРасходованиеСредств.Найти(Стр.ЗаявкаНаРасходование, "Заявка");                
                Оплатить=ТекЗаявка.Оплатить;
            КонецЕсли;    
            
            Если Оплатить=0 Тогда
                Продолжить;
            КонецЕсли;
                
            СтрокаПлатеж=Док.РасшифровкаПлатежа.Добавить();
            Если Оплатить > Стр.СуммаПлатежа Тогда
                СтрокаПлатеж.СуммаВзаиморасчетов=Стр.СуммаВзаиморасчетов;
                СтрокаПлатеж.СуммаПлатежа = Стр.СуммаПлатежа;
                Оплатить=Оплатить-Стр.СуммаПлатежа;
            Иначе    
                СтрокаПлатеж.СуммаВзаиморасчетов=Оплатить;
                СтрокаПлатеж.СуммаПлатежа = Оплатить;
                Оплатить=0;
            КонецЕсли;    
                            
            СтрокаПлатеж.КурсВзаиморасчетов      = Док.КурсДокумента;
            СтрокаПлатеж.КратностьВзаиморасчетов = Док.КратностьДокумента;
            СтрокаПлатеж.СтавкаНДС                         = Док.Контрагент.ОсновнойНДС;
            СтрокаПлатеж.Сделка                             = Стр.Сделка;
            СтрокаПлатеж.ДокументРасчетовСКонтрагентом     = Стр.ДокументРасчетовСКонтрагентом;
            СтрокаПлатеж.ДоговорКонтрагента                 = Стр.ДоговорКонтрагента;
            
            Попытка
                
                Если ЗначениеЗаполнено(Стр.Сделка) И ТипЗнч(Стр.Сделка) = Тип("ДокументСсылка.ЗаказПоставщику") И Не ЗначениеЗаполнено(Стр.ДокументРасчетовСКонтрагентом) Тогда
                    
                    Док.ДатаРасчетов = Стр.Сделка.ДатаПоступления;
                    
                Иначе
                    
                    ДатаРасчетовНовая = Основание.Дата;
                    Если ДатаРасчетовНовая = Неопределено Тогда
                        ДатаРасчетовНовая = ТекущаяДата();
                    КонецЕсли;    
                    Док.ДатаРасчетов=ДатаРасчетовНовая;
                    
                КонецЕсли;
                
                Если ЗначениеЗаполнено(Стр.ДокументРасчетовСКонтрагентом) И ТипЗнч(Стр.ДокументРасчетовСКонтрагентом) = Тип("ДокументСсылка.ПоступлениеТоваровУслуг") Тогда
                    
                    Док.ДатаРасчетов = Стр.ДокументРасчетовСКонтрагентом.Дата;    
                    
                КонецЕсли;
                
            Исключение
                
            КонецПопытки;
            
            УправлениеДенежнымиСредствами.ПересчитатьСуммуНДС(СтрокаПлатеж);
            
            СтрокаПлатеж.СтатьяДвиженияДенежныхСредств     = Стр.СтатьяДвиженияДенежныхСредств;
            СтрокаПлатеж.Проект                             = Стр.Проект;
            СтрокаПлатеж.ДокументПланированияПлатежа     = Стр.ЗаявкаНаРасходование;
            СтрокаПлатеж.КурсВзаиморасчетовПлан             = СтрокаПлатеж.КурсВзаиморасчетов;
            СтрокаПлатеж.СуммаПлатежаПлан                 = СтрокаПлатеж.СуммаПлатежа;    
            
            Зая =Стр.ЗаявкаНаРасходование;
        КонецЦикла;
15 Classic
 
24.06.15
16:32
На вскидку Заявка делает движения в остаточный регистр, платежка списывает. Достаточно по регистру остатки посмотреть и все.
16 ColonelAp4u
 
24.06.15
16:36
(15) есть документы которые не делают списание с этого регистра но могут уменьшить долг по документу, корректировка бухгалтерская, возврат товаров. а в взаиморасчеты они попадают по этому беру от туда инфу
17 ColonelAp4u
 
24.06.15
16:45
Подскажите как можно ускорить?
18 ИУБиПовиц
 
24.06.15
16:46
(0) Вынесите запрос из цикла и делайте без отбора. Далее выгружайте в тз, а в цикле ищите по этой тз, будет на порядок быстрее, может и хватит этой оптимизации:)
19 Гёдза
 
24.06.15
16:46
что замер говорит?
20 ХардHard
 
24.06.15
16:47
(0) Перенеси вначале в запрос таблицу из которой ты берешь "Стр.ДоговорКонтрагента" и запрос по остаткам сделай по всем строкам этой таблицы .
У тебя останется один основной цикл "пока выборка.Следующий()".
Дальше убирай остальную муть потихоньку.
21 РазДва
 
24.06.15
16:47
(17) Тебе уже подсказали: получи все необходимые данные по всем документам расчетов до цикла в одном запросе, и убери все обращения через точку по ссылкам в цикле.
22 ХардHard
 
24.06.15
16:48
(21) По  моему скромному опыту, эти обращения через точку не сильно влияют.
23 zak555
 
24.06.15
16:49
(5) откажись от запросов в цикле
24 Fragster
 
гуру
24.06.15
16:56
(22) они сильно влияют, особенно на скуле при разнесенных серверах 1с и скуля
25 ХардHard
 
24.06.15
16:58
(24) С разнесенными давно не работал . А так у меня больше КонецЦикла обычно жрет.
26 РазДва
 
24.06.15
16:58
(22) Не имею понятия, сколько здесь уходило процентов на эти точки, но подозреваю, что прилично. Пусть ТС замер производительности хоть сделает, убедится.
Почитай рекомендации 1С, давно уж твердят, что нужно минимизировать количество дерганий сервера. За точку по ссылке в цикле, по-моему, на экзамене  на специалиста сразу "не сдал" записывают, без учета твоего скромного опыта.
Каждая точка это метнутся на сервер, считать весь объект в память. На случай, если от точки не избавиться, придумали функцию ОбщегоНазначения.ПолучитьЗначениеРеквизита
27 ХардHard
 
24.06.15
17:00
(26) А кто тебе сказал, что я этого не делаю? Я лишь говорю, что ТС не так много выиграет в производительности и дел у него итак много. Ну может 10% он выиграет,хотя сомневаюсь.
28 РазДва
 
24.06.15
17:12
(27) Как-то встречал доработку: в обработке проведения был организован цикл по товарам, в котором использовалась безобидная неприметная строка с "Номенклатура.КакойТоРеквизит". В результате на документах с кучей строк(десятки тысяч) эта строка занимала более 90% времени. Была даже сделана отдельная обработка, чтобы бить эти документы кусочками по тысяче, иначе хрен дождешься проведения, а всё в этот момент заблокировано.
29 Fragster
 
гуру
24.06.15
17:13
(27) видел как-то как
Выборка.Контрагент.Наименование
Выборка.Контрагент.ИНН
И прочие получения реквизитов
занимали в сумме 80% обработки
30 ХардHard
 
24.06.15
17:14
(28) Лучше "Номенклатура.КакойТоРеквизит.КакойТоРеквизит" %)
31 Fragster
 
гуру
24.06.15
17:14
т.е. для одной строки - несколько процентов, для всех строк подобного получения - куча времени.
32 ХардHard
 
24.06.15
17:15
Тут у ТСа пострашнее вещи, чем ваши "." %)
33 РазДва
 
24.06.15
17:19
(32) в выложенном цикле у него и нет ничего больше, я уверен эти точки у него выполняются дольше, чем его официальный запрос в цикле по остаткам.
34 ХардHard
 
24.06.15
17:21
(33) Думаю, замера мы тут не дождемся. Там кроме точек и запроса в цикле ничего не находишь?
35 hhhh
 
24.06.15
17:22
(34) по опыту очень удобно считать запрос в цикле типа Стр.Сделка.ДатаПоступления увеличивает время выполнения в 60 раз.

То есть например обычная программа выполняется 2 сек., значит программа с точками будет выполняться 2 минуты. Это уже проверено многократно. И замеряит нечего.
36 ХардHard
 
24.06.15
17:25
(35) обычная программа выполняется 2 сек., значит программа с точками будет выполняться 2 минуты

Это 5. Пошел я домой.
37 hhhh
 
24.06.15
17:26
(36) давай
38 ColonelAp4u
 
24.06.15
17:31
НайденныеСтроки есть массив в котором хранятся все строки из заявки. Как мне его запихнуть в запрос в временную табл? сори в 1С еще не во всех аспектах разобрался, поэтому спрашиваю даже такой вопрос!
39 Loki Evil
 
24.06.15
17:41
(38) чаще всего просто записывать перед заполнением, а дальше уже из бд получают либо вложенным запросом - строки документа по ссылке, либо в отдельную временную таблицу и потом уже работают с ней.

Либо выгружают скажем колонку номенклатуры в массив и передают в запрос, в запросе пишется условие где .Номенклатура в (&МассивНоменклатуры) - скобки тут обязательно