После обновления конфигурации «1С:Управление торговлей 11» (начиная с релизов ветки 11.5.17 и вплоть до LTS-релизов 11.5.27) пользователи нередко сталкиваются с неприятной ошибкой: при попытке сформировать отчет «Задолженность клиента» или «Ведомость расчетов» непосредственно из формы документа «Реализация товаров и услуг» сеанс 1С намертво зависает. При этом, если открыть тот же самый отчет отдельно из раздела отчетов, он формируется штатно и без задержек.
Разберем природу этого поведения, выясним причину разницы в работе файловых и клиент-серверных баз, а также рассмотрим пошаговое исправление узкого места в программном коде.
Проанализируем механику работы системы при формировании отчетов по взаиморасчетам. Существует принципиальная разница между автономным открытием отчета и его вызовом из контекста первичного документа:
ВзаиморасчетыСервер, в частности процедура ПолучитьОбъектыРасчетовДляОтбораОтчета().В этой процедуре формируется запрос к физической таблице движений регистра РасчетыСКлиентами и справочнику ОбъектыРасчетов. В типовом тексте запроса для порядка расчетов «По заказам / накладным» используется соединение:
ПО Расчеты.ПродажаПоЗаказу = ОбъектыРасчетов.Объект
Если в базе данных велся учет с накладными без заказов, реквизит ПродажаПоЗаказу в регистре может оставаться пустым. Кроме того, данный реквизит может иметь несоответствующий тип, из-за чего сравнение с полем ОбъектыРасчетов.Объект не может завершиться успешно по индексам.
Рассмотрим подробнее поведение СУБД при выполнении неоптимального соединения больших таблиц:
Для устранения проблемы выясним точное место в конфигурации. Перейдем в общий модуль ВзаиморасчетыСервер и найдем процедуру ПолучитьОбъектыРасчетовДляОтбораОтчета().
В блоке формирования текста запроса для условия Если СтруктураПараметров.ЭтоПродажаЗакупка Тогда заменим связь по реквизиту ПродажаПоЗаказу на обращение к полю Регистратор.
Посмотрим на пример исправленного фрагмента запроса:
Если СтруктураПараметров.ЭтоПродажаЗакупка Тогда
ТекстЗапроса = ТекстЗапроса + ОбщегоНазначенияУТ.РазделительЗапросовВОбъединении() + "
|ВЫБРАТЬ
| ОбъектыРасчетовДоговор.Ссылка
|ИЗ
| ВтОбъектРасчетов КАК ВтОбъектРасчетов
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ОбъектыРасчетов КАК ОбъектыРасчетов
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ОбъектыРасчетов КАК ОбъектыРасчетовДоговор
| ПО ОбъектыРасчетов.Договор = ОбъектыРасчетовДоговор.Объект
| И НЕ ОбъектыРасчетов.ПометкаУдаления
| И НЕ ОбъектыРасчетов.ТолькоОстатки
| ПО ВтОбъектРасчетов.ОбъектРасчетов = ОбъектыРасчетов.Ссылка
|ГДЕ
| ВтОбъектРасчетов.ПорядокРасчетов = ЗНАЧЕНИЕ(Перечисление.ПорядокРасчетов.ПоДоговорамНакладным)
|
|ОБЪЕДИНИТЬ ВСЕ
|
|ВЫБРАТЬ
| ОбъектыРасчетов.Ссылка
|ИЗ
| ВтОбъектРасчетов КАК ВтОбъектРасчетов
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.РасчетыСКлиентами КАК Расчеты
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ОбъектыРасчетов КАК ОбъектыРасчетов
| ПО (Расчеты.Регистратор = ОбъектыРасчетов.Объект)
| И НЕ ОбъектыРасчетов.ПометкаУдаления
| И НЕ ОбъектыРасчетов.ТолькоОстатки
| ПО (ВтОбъектРасчетов.ОбъектРасчетов = Расчеты.ОбъектРасчетов)
|ГДЕ
| ВтОбъектРасчетов.ПорядокРасчетов = ЗНАЧЕНИЕ(Перечисление.ПорядокРасчетов.ПоЗаказамНакладным)
Разберем изменения: условие Расчеты.ПродажаПоЗаказу = ОбъектыРасчетов.Объект заменено на Расчеты.Регистратор = ОбъектыРасчетов.Объект. Поскольку поле Регистратор всегда заполнено ссылкой на первичный документ и входит в кластерные индексы регистра, СУБД мгновенно сопоставляет накладную со справочником объектов расчетов без выполнения ресурсоемких сканирований всей таблицы.
Для того чтобы доработка не создавала проблем при дальнейших обновлениях, выполним следующие шаги:
&ИзменениеИКонтроля или перехватом &Вместо.ЗаданияКРасчетуСКлиентами.