Ускорение запросов путем уменьшения типов до реально используемых

02.09.24

Разработка - Запросы

Функция, которая сокращает типы в ВТ для последующих запросов. В ряде случае позволяет существенно ускорить запросы.

Рассмотрим ситуацию.

Допустим, есть пакет запросов с запросом:

ВЫБРАТЬ Регистратор ИЗ ПОМЕСТИТЬ тт Регистр.Бухгалтерии.Хозрасчетный ГДЕ Период = Дата(2024,1,1)

Запрос вернет все типы документов, являющиеся регистратором РБ Хозрасчетный

Далее в запросе обращаемся к полю Регистратор.Дата или Регистратор.Номер (как ни странно, такое бывает и такое может вынести сам пользователь в СКД) - это вызовет соединение со всеми типами документа. Оптимизатор с высокой долей вероятности не сможет оптимизировать запрос.

Моя функция создает для каждой временной таблицы новую временную таблицу, но тип будет сокращен только для типов, реально присутствующих в таблице через 

ВЫБОР
   КОГДА Тип() ТОГДА ВЫРАЗИТЬ()
КОНЕЦ



Сам код:

 
Функция УменьшитьТипВременнойТаблицы_Выгрузить(Запрос, ПоместитьРезультатВМенеджерПодИменем=неопределено, удалятьВконцеПромежуточныеВременныеТаблицы = ложь) экспорт
    
    Если Запрос.МенеджерВременныхТаблиц = неопределено тогда 
        Запрос.МенеджерВременныхТаблиц = новый МенеджерВременныхТаблиц;
    КонецЕсли;
    
    
    ЗапросТекст = Запрос.Текст;
    
    схемазапроса = новый СхемаЗапроса();
    схемазапроса.УстановитьТекстЗапроса(ЗапросТекст);  
    МассивРезультатов = новый Массив;      
    ЗамерВремени = новый Массив; 
    номерЗапроса = 1;
    НакопленныйТекстЗапроса = "";   
    УдаляемыеВКонцеТаблицы = новый Массив;
    
    
    для каждого стрсхемазапроса из схемазапроса.ПакетЗапросов цикл
        Если ТипЗнч(стрсхемазапроса) = тип("ЗапросВыбораСхемыЗапроса") тогда
            стрСхемазапросаТаблицаДляПомещения = стрСхемаЗапроса.ТаблицаДляПомещения; 
            ВременноеИмяТаблицы = "птгш_"+стрСхемазапросаТаблицаДляПомещения;
            Если стрСхемазапросаТаблицаДляПомещения<>"" тогда
                стрсхемазапроса.ТаблицаДляПомещения = ВременноеИмяТаблицы;
                Запрос.Текст = стрсхемазапроса.ПолучитьТекстЗапроса(); 
                
                Запрос.Текст = ОбработкаНесуществующихПолей(Запрос.Текст,НакопленныйТекстЗапроса);
                
                ТекущаяДатаДоЗамера = ТекущаяДата();  
                /// запрос основной 
                пока истина цикл
                    попытка
                        Запрос.Выполнить(); 
                        прервать;
                    исключение
                        Ошибка = ОписаниеОшибки();
                        Если Ошибка="" тогда 
                            прервать;
                        конецЕсли;                               
                        
                        ЗапросТекст2 = Запрос.Текст;

                        ПодСтроки = новый Массив;
                        ПодСтроки.Добавить("{ОбщийМодуль.озОбработкаЗапросов.Модуль(");
                        ПодСтроки.Добавить(")}: Ошибка при вызове метода контекста (Выполнить): {("); 
                        ПодСтроки.Добавить(","); 
                        ПодСтроки.Добавить(")}: Несовместимые типы ""ВЫРАЗИТЬ""");
                        ПодСтроки.Добавить(Символы.ПС+"");
                        ПодСтроки.Добавить("<<?>>");
                        М = РазборСтроки(Ошибка,ПодСтроки);  
                        Если М<>неопределено тогда 

                            НомерСтрокиОткудаУдаляем = Число(М[2]);
                            ПозицияСтрокиОткудаУдаляем = Число(М[3])+стрдлина(М[5])-1;
                            УдаляемаяСтрока = М[6];            
                            ПозицияСтроки = СтрНайти(ЗапросТекст2,Символы.ПС,,,НомерСтрокиОткудаУдаляем-1);  
                            
                            ЕстьПерваяСкобка = ложь;                   
                            КоличествоСкобок = 0;
                            п2 = 1;
                            пока истина цикл
                                
                                Если сред(УдаляемаяСтрока,п2,1)=")" тогда 
                                    КоличествоСкобок = КоличествоСкобок - 1;
                                иначеЕсли сред(УдаляемаяСтрока,п2,1)="(" тогда 
                                    КоличествоСкобок = КоличествоСкобок + 1;
                                    ЕстьПерваяСкобка = истина;
                                КонецЕсли;                           
                                п2 = п2 +1;
                                
                                Если ЕстьПерваяСкобка И КоличествоСкобок = 0 тогда 
                                    прервать;
                                КонецЕсли;
                            КонецЦикла;   
                            УдаляемаяСтрока = сред(УдаляемаяСтрока,1,п2);
                                
                            НачалоЗаменяемойСтроки = стрНайти(ЗапросТекст2,УдаляемаяСтрока,НаправлениеПоиска.СКонца,ПозицияСтроки+стрдлина(М[6]));

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

Функция НайтиТип(Тип)
    Если Тип = Тип("Строка") тогда
        возврат "Строка"
    ИначеЕсли Тип = Тип("Дата") тогда
        возврат "Дата"
    ИначеЕсли Тип = Тип("Булево") тогда
        возврат "Булево"
    ИначеЕсли Тип = Тип("Число") тогда
        возврат "Число"
    ИначеЕсли Тип = Тип("неопределено") тогда
        возврат "неопределено"
    ИначеЕсли Тип = Тип("NULL") тогда
        возврат "NULL"
    иначе 
        возврат Метаданные.НайтиПоТипу(Тип).ПолноеИмя()
    КонецЕсли;
    
КонецФункции

Функция РазборСтроки(знач СтрокаРазбора, знач ШаблонПодстроки) 
    
    Результат = новый Массив;
    
    для каждого стрШаблонПодстроки из ШаблонПодстроки цикл
        НайденнаяПозиция = стрНайти(СтрокаРазбора,стрШаблонПодстроки);
        Если НайденнаяПозиция>0 тогда 
            Результат.Добавить(сред(СтрокаРазбора,1,НайденнаяПозиция-1));
            СтрокаРазбора = сред(СтрокаРазбора,НайденнаяПозиция+стрдлина(стрШаблонПодстроки));
        иначе
            возврат неопределено;
        КонецЕсли;
        
    КонецЦикла;       
    Результат.Добавить(СтрокаРазбора);
    возврат Результат;
    
КонецФункции

Функция ОбработкаНесуществующихПолей(ЗапросТекст2,НакопленныйТекстЗапроса)
    
    ПоследняяСтрокаНакопленногоЗапроса = СтрЧислоСтрок(?(НакопленныйТекстЗапроса="","",НакопленныйТекстЗапроса+";"+Символы.ПС));
    
    Пока истина цикл
        
        ПовторноОбработатьОшибку = Ложь;     
        попытка                                                                                   
            
            ЗапросТекст3 = ?(НакопленныйТекстЗапроса="","",НакопленныйТекстЗапроса+";"+Символы.ПС) + ЗапросТекст2;
            
            схемазапроса2 = новый СхемаЗапроса();
            схемазапроса2.УстановитьТекстЗапроса(ЗапросТекст3);
        исключение
            Ошибка = ОписаниеОшибки();
            
            ПодСтроки = новый Массив;
            ПодСтроки.Добавить("{ОбщийМодуль.озОбработкаЗапросов.Модуль(");
            ПодСтроки.Добавить(")}: Ошибка при вызове метода контекста (УстановитьТекстЗапроса): {("); 
            ПодСтроки.Добавить(","); 
            ПодСтроки.Добавить(")}: Поле не найдено """);
            ПодСтроки.Добавить(""""+Символы.ПС);
            ПодСтроки.Добавить("<<?>>");
            М = РазборСтроки(Ошибка,ПодСтроки);  
            Если М<>неопределено тогда 
                
                НомерСтрокиОткудаУдаляем = Число(М[2])-ПоследняяСтрокаНакопленногоЗапроса;
                ПозицияСтрокиОткудаУдаляем = Число(М[3])+стрдлина(М[6])-1;
                УдаляемаяСтрока = М[4];            
                ПозицияСтроки = СтрНайти(ЗапросТекст2,Символы.ПС,,,НомерСтрокиОткудаУдаляем-1);  
                
                НачалоЗаменяемойСтроки = стрНайти(ЗапросТекст2,УдаляемаяСтрока,НаправлениеПоиска.СКонца,ПозицияСтроки+ПозицияСтрокиОткудаУдаляем);
                ЗапросТекст2 = сред(ЗапросТекст2,1,НачалоЗаменяемойСтроки-1)+"NULL"+
                сред(ЗапросТекст2,НачалоЗаменяемойСтроки+стрДлина(УдаляемаяСтрока));
                ПовторноОбработатьОшибку = Истина;
                
            иначе 
                ПодСтроки = новый Массив;
                ПодСтроки.Добавить("{ОбщийМодуль.озОбработкаЗапросов.Модуль(");
                ПодСтроки.Добавить(")}: Ошибка при вызове метода контекста (УстановитьТекстЗапроса): {("); 
                ПодСтроки.Добавить(","); 
                ПодСтроки.Добавить(")}: Несовместимые типы ""ССЫЛКА""");
                ПодСтроки.Добавить(Символы.ПС+"КОГДА");
                ПодСтроки.Добавить("<<?>>");
                М = РазборСтроки(Ошибка,ПодСтроки);  
                Если М<>неопределено тогда 

                    НомерСтрокиОткудаУдаляем = Число(М[2])-ПоследняяСтрокаНакопленногоЗапроса;
                    ПозицияСтрокиОткудаУдаляем = Число(М[3])+стрдлина(М[5])-1;
                    УдаляемаяСтрока = М[5];            
                    ПозицияСтроки = СтрНайти(ЗапросТекст2,Символы.ПС,,,НомерСтрокиОткудаУдаляем-1);  
                    
                    НачалоЗаменяемойСтроки = стрНайти(ЗапросТекст2,УдаляемаяСтрока,НаправлениеПоиска.СКонца,ПозицияСтроки+Число(М[3])+стрдлина(М[5]));

                    УдаляемаяСтрока = М[6];            
                    КонецЗаменяемойСтроки = стрНайти(ЗапросТекст2,УдаляемаяСтрока,НаправлениеПоиска.СНачала,ПозицияСтроки)+стрдлина(УдаляемаяСтрока);
                    
                    ЗапросТекст2 = сред(ЗапросТекст2,1,НачалоЗаменяемойСтроки-1)+" ЛОЖЬ "+
                    
                    
                    ОбработкаКогдаЛожь(сред(ЗапросТекст2,КонецЗаменяемойСтроки));
                    ПовторноОбработатьОшибку = Истина;
                    
                иначе     
                    ПодСтроки = новый Массив;
                    ПодСтроки.Добавить("{ОбщийМодуль.озОбработкаЗапросов.Модуль(");
                    ПодСтроки.Добавить(")}: Ошибка при вызове метода контекста (УстановитьТекстЗапроса): {("); 
                    ПодСтроки.Добавить(","); 
                    ПодСтроки.Добавить(")}: Несовместимые типы ""ССЫЛКА""");
                    ПодСтроки.Добавить(Символы.ПС+"");
                    ПодСтроки.Добавить("<<?>>");
                    М = РазборСтроки(Ошибка,ПодСтроки);  
                    Если М<>неопределено тогда 

                        НомерСтрокиОткудаУдаляем = Число(М[2])-ПоследняяСтрокаНакопленногоЗапроса;
                        ПозицияСтрокиОткудаУдаляем = Число(М[3])+стрдлина(М[5])-1;
                        УдаляемаяСтрока = М[5];            
                        ПозицияСтроки = СтрНайти(ЗапросТекст2,Символы.ПС,,,НомерСтрокиОткудаУдаляем-1);  
                        
                        НачалоЗаменяемойСтроки = стрНайти(ЗапросТекст2,УдаляемаяСтрока,НаправлениеПоиска.СКонца,ПозицияСтроки+стрдлина(М[5]));

                        УдаляемаяСтрока = М[6];            
                        КонецЗаменяемойСтроки = стрНайти(ЗапросТекст2,УдаляемаяСтрока,НаправлениеПоиска.СНачала,ПозицияСтроки)+стрдлина(УдаляемаяСтрока);
                        
                        ЗапросТекст2 = сред(ЗапросТекст2,1,НачалоЗаменяемойСтроки-1)+" ложь "+
                        
                        
                        сред(ЗапросТекст2,КонецЗаменяемойСтроки);
                        ПовторноОбработатьОшибку = Истина;
                        
                    иначе       
                        
                        
                    ПодСтроки = новый Массив;
                    ПодСтроки.Добавить("{ОбщийМодуль.озОбработкаЗапросов.Модуль(");
                    ПодСтроки.Добавить(")}: Ошибка при вызове метода контекста (УстановитьТекстЗапроса): {("); 
                    ПодСтроки.Добавить(","); 
                    ПодСтроки.Добавить(")}: Несовместимые типы ""ВЫРАЗИТЬ""");
                    ПодСтроки.Добавить(Символы.ПС+"");
                    ПодСтроки.Добавить("<<?>>");
                    М = РазборСтроки(Ошибка,ПодСтроки);  
                    Если М<>неопределено тогда 

                        НомерСтрокиОткудаУдаляем = Число(М[2])-ПоследняяСтрокаНакопленногоЗапроса;
                        ПозицияСтрокиОткудаУдаляем = Число(М[3])+стрдлина(М[5])-1;
                        УдаляемаяСтрока = М[6];            
                        ПозицияСтроки = СтрНайти(ЗапросТекст2,Символы.ПС,,,НомерСтрокиОткудаУдаляем-1);  
                        
                        ЕстьПерваяСкобка = ложь;  
                        КоличествоСкобок = 0;
                        п2 = 1;
                        пока истина цикл
                            
                            Если сред(УдаляемаяСтрока,п2,1)=")" тогда 
                                КоличествоСкобок = КоличествоСкобок - 1;
                            иначеЕсли сред(УдаляемаяСтрока,п2,1)="(" тогда 
                                КоличествоСкобок = КоличествоСкобок + 1;
                                ЕстьПерваяСкобка = истина;
                            КонецЕсли;                           
                            п2 = п2 +1;
                            
                            Если ЕстьПерваяСкобка И КоличествоСкобок = 0 тогда 
                                прервать;
                            КонецЕсли;
                        КонецЦикла;   
                        УдаляемаяСтрока = сред(УдаляемаяСтрока,1,п2);
                            
                        НачалоЗаменяемойСтроки = стрНайти(ЗапросТекст2,УдаляемаяСтрока,НаправлениеПоиска.СКонца,ПозицияСтроки+стрдлина(М[6]));
                        КонецЗаменяемойСтроки = НачалоЗаменяемойСтроки+стрдлина(УдаляемаяСтрока);

                        ЗапросТекст2 = сред(ЗапросТекст2,1,НачалоЗаменяемойСтроки-1)+" NULL "+
                        
                        
                        сред(ЗапросТекст2,КонецЗаменяемойСтроки);
                        ПовторноОбработатьОшибку = Истина;
                        
                    иначе     
                        вызватьИсключение Ошибка;
                    
                    КонецЕсли;
                    
                    КонецЕсли;
                
                КонецЕсли;
            КонецЕсли;
            
            
        КонецПопытки;  
        
        Если    не ПовторноОбработатьОшибку тогда 
            прервать;
        КонецЕсли;
        
    КонецЦикла;     
    
    
    возврат ЗапросТекст2;
    
КонецФункции


Функция ОбработкаКогдаЛожь(Текст2)
    Результат = "";
    Текст = нрег(Текст2);
    Токены = стрразделить("выбор,когда,тогда,конец,иначе",",");
    
    СчетчикВложенности = 0;
    Начпоз = 1;
    пока истина цикл
        токен2 = "";
        Поз2 = 1000000;
        для каждого стрТокены из Токены цикл
            Поз = стрнайти(Текст,стрТокены,,Начпоз);
            Если Поз<>0 И Поз<Поз2 тогда 
                 Поз2=Поз;
                 токен2 = стрТокены;
             КонецЕсли;
         КонецЦикла;
         Если Токены.Найти(токен2)=неопределено тогда 
             прервать;
         КонецЕсли;
         
        Если токен2="выбор" тогда
            СчетчикВложенности=СчетчикВложенности+1;
        иначеЕсли токен2="конец" тогда
            СчетчикВложенности=СчетчикВложенности-1; 
        ИначеЕсли (токен2="когда" или токен2="иначе") И СчетчикВложенности=0 тогда
            Рез = Поз2;
            прервать;
        КонецЕсли;
         
         Начпоз = Поз2+1;
     КонецЦикла;
     возврат " тогда неопределено "+сред(Текст2,Рез);
     
КонецФункции
     
        
    
Функция ОбработкаМакетаКомпоновки(МакетКомпоновки,МенеджерВременныхТаблиц2) экспорт   
    
    для каждого стрНабор из МакетКомпоновки.НаборыДанных цикл
        Запрос = новый запрос(стрНабор.Запрос);
        
        Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц2;
        
        для каждого стрПараметр из МакетКомпоновки.ЗначенияПараметров цикл
            Запрос.УстановитьПараметр(стрПараметр.Имя,стрПараметр.Значение);
        КонецЦикла;
        Результат = УменьшитьТипВременнойТаблицы_Выгрузить(Запрос,стрНабор.Имя,истина);
        
        
        
        РезультатЗапрос = " Выбрать "+символы.ПС;
        МассивПолей = новый Массив;
        для каждого стрПоля из стрНабор.Поля цикл
            МассивПолей.Добавить(" Т."+стрПоля.Имя+" как "+стрПоля.Имя);
        КонецЦикла;                                                     
        МассивПолей = ОбщегоНазначенияКлиентСервер.СвернутьМассив(МассивПолей);
        РезультатЗапрос = " Выбрать "+стрсоединить(МассивПолей,","+символы.ПС)+символы.ПС+" из "+стрНабор.Имя + " как Т";
        стрНабор.Запрос = РезультатЗапрос;
        
    КонецЦикла;
    
    возврат МакетКомпоновки;
КонецФункции

В ряде случаев ускорение получается примерно в 2 раза

В чем сложность? Дело в том, что если мы сократили тип в запросе, но вызываем Регистратор.ТутПолеДокумента,  1С генерирует ошибку, т.к. поле "ТутПолеДокумента" теперь не встречается. А в случае использования СхемыДанных, если поле также встречается в ВЫБОР, ошибки не возникают.

Писал предложение на этот счет в 1С

оптимизация запросов

См. также

Инструментарий разработчика Роли и права Запросы СКД Программист Руководитель проекта Платформа 1С v8.3 Управляемые формы Запросы Система компоновки данных Платные (руб)

Инструменты для разработчиков 1С 8.3: Infostart Toolkit. Автоматизация и ускорение разработки на управляемых формах. Легкость работы с 1С.

15500 руб.

02.09.2020    183650    1023    403    

966

Обновление 1С Запросы Программист Платформа 1С v8.3 1С:ERP Управление предприятием 2 Абонемент ($m)

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

2 стартмани

06.02.2025    2147    17    XilDen    26    

36

Запросы Программист Платформа 1С v8.3 Запросы 1C:Бухгалтерия Бесплатно (free)

В статье приведена удобная возможность отладки исполняемого запроса динамического списка.

03.12.2024    5621    artemusII    11    

23

Запросы Программист Бесплатно (free)

Увидел cheatsheet по SQL и захотелось нарисовать подобное, но про запросы.

18.10.2024    13030    sergey279    18    

65

Запросы Программист Платформа 1С v8.3 Запросы 1C:Бухгалтерия Бесплатно (free)

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

11.10.2024    8125    XilDen    36    

90

СКД Механизмы типовых конфигураций Запросы Программист Платформа 1С v8.3 1С:Зарплата и кадры государственного учреждения 3 1С:Зарплата и Управление Персоналом 3.x Россия Бесплатно (free)

Работая с типовыми отчетами в конфигурациях «Зарплата и управление персоналом, редакция 3», «Зарплата и кадры государственного учреждения, редакция 3» и подобных, в схемах компоновки данных можно встретить конструкции запросов, которые обращаются к некоторым виртуальным таблицам.

20.08.2024    3131    PROSTO-1C    0    

23

Запросы Программист Запросы Бесплатно (free)

Отлаживая взаимодействие с базой данных, мы регулярно сталкиваемся с зависающими или подозрительно долго выполняющимися обращениями, негативно влияющими на производительность. О том, как в PostgreSQL выявить подозрительные запросы, основываясь на доступной о них информации, расскажем в статье.

16.08.2024    10711    user1840182    5    

29
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. K_A_O 551 03.09.24 08:47 Сейчас в теме
Если можем определить реально используемые типы документов, то условие ССЫЛКА тоже уменьшает количество соединений

ВЫБРАТЬ Регистратор ИЗ ПОМЕСТИТЬ тт Регистр.Бухгалтерии.Хозрасчетный ГДЕ Период = Дата(2024,1,1)
ГДЕ (Регистратор ССЫЛКА Документ.ОперацияБух ИЛИ Регистратор ССЫЛКА Документ.АвансовыйОтчет ...)
2. s22 23 03.09.24 09:13 Сейчас в теме
(1)
Регистратор ССЫЛКА Документ.ОперацияБух ИЛИ Регистратор ССЫЛКА Документ.АвансовыйОтчет ...


проблема что мы знание об этих типах получим только после выполнения запроса
3. K_A_O 551 03.09.24 10:38 Сейчас в теме
(2) В общем случае "да", и я ничуть не критикую это решение. Но если можно определить состав типов документов (например для определенных задач могут быть только определенные документы) - то простое условие "где" очень даже ускоряет.
4. s22 23 03.09.24 13:55 Сейчас в теме
(3) с этим не поспоришь, но заранее знать всегда не получиться, а оптимизатор при большом количестве соединений ведёт себя плохо.

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

Вообще хотелось бы такую оптимизацию на уровне платформы
5. acces969 370 04.09.24 08:02 Сейчас в теме
(1) ИЛИ, так же как и КОГДА ТОГДА в условии или соединении серьезно замедляет выполнение запроса
6. s22 23 05.09.24 11:18 Сейчас в теме
(5)
(1) ИЛИ, так же как и КОГДА ТОГДА в условии или соединении серьезно замедляет выполнение запроса


они в выборе.
7. user1880116 05.09.24 19:23 Сейчас в теме
(5)
серьезно замедляет
А разверни свою мысль, пожалуйста. Когда именно и всё такое.
8. acces969 370 06.09.24 07:39 Сейчас в теме
(7) Дизъюнкция в условии отбора или соединении таблиц приводит к перебору всех записей, поэтому скорость значительно снижается. Проверяли это на спор, разница была видна. В секундах не скажу, не помню, это вы лучше сами проверьте)
9. s22 23 06.09.24 09:29 Сейчас в теме
(8)
(7) Дизъюнкция в условии отбора или соединении таблиц приводит к перебору всех записей, поэтому скорость значительно снижается. Проверяли это на спор, разница была видна. В секундах не скажу, не помню, это вы лучше сами проверьте)

зависит от версии
например тип в (тут типы) не преводит к дизьюкции
а Т.ссылка ссылка документ..... или Т.ссылка ссылка документ.....
может приводить, а может не приводит в зависимости от того сможет свернуть скл или нет
10. user1880116 06.09.24 11:48 Сейчас в теме
(8)
Дизъюнкция
Ух ты, слова-то какие!

А расскажи тогда, как работает условие ГДЕ Поле В (Значение1, Значение2). Желательно с планом запроса.
11. acces969 370 06.09.24 11:56 Сейчас в теме
12. user1880116 06.09.24 12:21 Сейчас в теме
(11) Мне нужна именно твоя интерпретация. Что там написано - я знаю, спасибо.
13. alex_sayan 58 09.09.24 18:17 Сейчас в теме
14. s22 23 12.10.24 14:21 Сейчас в теме
(13) большая часть кода это обход ошибки 1с.
Разница между работой запроса и схемы запроса
15. alex_sayan 58 12.10.24 20:42 Сейчас в теме
(14) дело вовсе не в схеме запроса
Оставьте свое сообщение