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

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С

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

См. также

SALE! 15%

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

Набор инструментов программиста и специалиста 1С для всех конфигураций на управляемых формах. В состав входят инструменты: Консоль запросов, Консоль СКД, Консоль кода, Редактор объекта, Анализ прав доступа, Метаданные, Поиск ссылок, Сравнение объектов, Все функции, Подписки на события и др. Редактор запросов и кода с раскраской и контекстной подсказкой. Доработанный конструктор запросов тонкого клиента. Продукт хорошо оптимизирован и обладает самым широким функционалом среди всех инструментов, представленных на рынке.

10000 руб.

02.09.2020    159423    872    399    

861

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

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

18.10.2024    9875    sergey279    18    

64

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

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

11.10.2024    5167    XilDen    36    

80

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

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

16.08.2024    7901    user1840182    5    

28

Математика и алгоритмы Запросы Программист Платформа 1С v8.3 Запросы Бесплатно (free)

Рассмотрим быстрый алгоритм поиска дублей с использованием hash функции по набору полей шапки и табличных частей.

08.07.2024    2393    ivanov660    9    

22

Запросы СКД Программист Стажер Система компоновки данных Россия Бесплатно (free)

Часто при разработке отчетов в СКД возникает ситуация, когда не совсем понятно, почему отчет выводит не те данные, которые нужны, либо не выводит вовсе. Возникает потребность увидеть конечный запрос, который формирует СКД. Как это сделать, рассмотрим в этой статье.

15.05.2024    8684    implecs_team    6    

47

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

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

11.04.2024    3391    andrey_sag    10    

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

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


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

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

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


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

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

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