При разработке отчетов и контрольных процедур в конфигурации «1С:Бухгалтерия предприятия 3.0» разработчики нередко сталкиваются с падением скорости выполнения запросов по таблицам документов Документ.ПоступлениеТоваровУслуг. Возникает стереотип: «выборка по регистрам всегда работает быстрее, чем по документам». Давайте разберем, насколько оправдан такой подход при поиске дубликатов входящих номеров, выясним структуру типовых регистров и рассмотрим оптимальные варианты ускорения запросов.
Проанализируем структуру хранения данных. В конфигурации «Бухгалтерия предприятия 3.0» существует независимый регистр сведений ДанныеПервичныхДокументов. Он используется для быстрого отображения списков и печати первичных документов.
В этом регистре присутствуют следующие поля:
Организация — организация документа;Документ — ссылка составного типа (включая ДокументСсылка.ПоступлениеТоваровУслуг);Номер и Дата — системные номер и дата документа;НомерВходящегоДокумента и ДатаВходящегоДокумента — реквизиты входящего документа контрагента.Однако реквизита Ответственный в регистре сведений ДанныеПервичныхДокументов нет. Если перед нами стоит задача найти дубликаты входящих номеров именно в разрезе ответственных менеджеров или пользователей, обращение к регистру приведет к необходимости левого соединения с таблицей самого документа. В таком случае выигрыш в производительности исчезает, а нагрузка на СУБД возрастает из-за лишних соединений с составным типом данных.
Выясним главные причины медленной работы запросов к табличной части документов:
НомерВходящегоДокумента и Ответственный в типовой конфигурации не индексируются. Поиск по ним на больших объемах данных вызывает полное сканирование таблицы (Full Table Scan).Рассмотрим, как правильно составить запрос к таблице Документ.ПоступлениеТоваровУслуг для выявления дублей на уровне сервера базы данных. Чтобы минимизировать передаваемый объем данных, используем группировку и фильтрацию с помощью предложения ИМЕЮЩИЕ.
ВЫБРАТЬ
Поступление.Организация КАК Организация,
Поступление.Контрагент КАК Контрагент,
Поступление.НомерВходящегоДокумента КАК НомерВходящегоДокумента,
Поступление.Ответственный КАК Ответственный,
КОЛИЧЕСТВО(Поступление.Ссылка) КАК КоличествоДублей
ИЗ
Документ.ПоступлениеТоваровУслуг КАК Поступление
ГДЕ
Поступление.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
И Поступление.НомерВходящегоДокумента <> ""
И НЕ Поступление.ПометкаУдаления
СГРУППИРОВАТЬ ПО
Поступление.Организация,
Поступление.Контрагент,
Поступление.НомерВходящегоДокумента,
Поступление.Ответственный
ИМЕЮЩИЕ
КОЛИЧЕСТВО(Поступление.Ссылка) > 1
Разберем ключевые моменты этого запроса:
Дата МЕЖДУ &ДатаНачала И &ДатаОкончания отсекает чтение лишних страниц данных, так как стандартный реквизит Дата проиндексирован платформой.НомерВходящегоДокумента <> "" исключает из тяжелой группировки документы без входящего номера.ИМЕЮЩИЕ КОЛИЧЕСТВО(Поступление.Ссылка) > 1 возвращает только те строки, где действительно есть дубли.Если отчет или обработка запускается пользователем с ограниченными правами, RLS существенно снижает скорость. Чтобы исключить наложение сложных условий проверки прав, выполним процедуру формирования на сервере с отключением контроля доступа.
Посмотрим на пример серверного кода:
&НаСервереБезКонтекста
Функция ПолучитьТаблицуДублей(ДатаНачала, ДатаОкончания)
УстановитьПривилегированныйРежим(Истина);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Поступление.Организация КАК Организация,
| Поступление.Контрагент КАК Контрагент,
| Поступление.НомерВходящегоДокумента КАК НомерВходящегоДокумента,
| Поступление.Ответственный КАК Ответственный,
| КОЛИЧЕСТВО(Поступление.Ссылка) КАК КоличествоДублей
|ИЗ
| Документ.ПоступлениеТоваровУслуг КАК Поступление
|ГДЕ
| Поступление.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
| И Поступление.НомерВходящегоДокумента <> """"
| И НЕ Поступление.ПометкаУдаления
|СГРУППИРОВАТЬ ПО
| Поступление.Организация,
| Поступление.Контрагент,
| Поступление.НомерВходящегоДокумента,
| Поступление.Ответственный
|ИМЕЮЩИЕ
| КОЛИЧЕСТВО(Поступление.Ссылка) > 1";
Запрос.УстановитьПараметр("ДатаНачала", ДатаНачала);
Запрос.УстановитьПараметр("ДатаОкончания", ДатаОкончания);
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
Если база данных содержит сотни тысяч документов за выбранный период и запрос продолжает работать долго, добавим индекс для реквизита без снятия конфигурации с поддержки:
ПоступлениеТоваровУслуг.НомерВходящегоДокумента устанавливаем свойство Индексировать в значение Индексировать.Напомним, что в типовой конфигурации «1С:Бухгалтерия предприятия 3.0» уже предусмотрены встроенные средства работы с дублями:
Организация, Контрагент и НомерВходящегоДокумента, информируя пользователя предупреждающим сообщением.