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