В процессе разработки и сопровождения систем на базе 1С часто возникает задача контроля данных. Одной из типичных ситуаций является поиск объектов (например, документов), для которых еще не созданы записи в определенных регистрах сведений — будь то регистр пломбировки, статусов или дополнительных реквизитов. В данной статье мы подробно разберем, как правильно составить такой запрос, проанализируем типичные ошибки и рассмотрим способы оптимизации производительности при работе с большими объемами данных.
Рассмотрим ситуацию, когда нам необходимо найти все документы ПриходнаяНакладная, информация о которых отсутствует в регистре сведений ПломбировкаДокументов. Основным механизмом для решения подобных задач в языке запросов 1С является ЛЕВОЕ СОЕДИНЕНИЕ в сочетании с проверкой на пустое значение (NULL).
Проанализируем структуру правильного запроса. Мы берем за основу таблицу документов и пытаемся "подклеить" к ней таблицу регистра по ссылке на документ. Если записи в регистре нет, поле из таблицы регистра примет значение NULL.
Рассмотрим пример кода:
ВЫБРАТЬ
ПриходнаяНакладная.Ссылка КАК Ссылка
ИЗ
Документ.ПриходнаяНакладная КАК ПриходнаяНакладная
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ПломбировкаДокументов КАК ПломбировкаДокументов
ПО ПриходнаяНакладная.Ссылка = ПломбировкаДокументов.Документ
ГДЕ
ПломбировкаДокументов.Документ ЕСТЬ NULL
Важный нюанс: Обратите внимание на условие связи в секции ПО. Типичной ошибкой начинающих разработчиков является обращение к реквизиту через точку, например: ПриходнаяНакладная.Ссылка = ПломбировкаДокументов.Документ.Ссылка. Это приводит к лишнему соединению с таблицей документа через поле регистра, что замедляет запрос и может привести к некорректной работе условия ЕСТЬ NULL. Всегда сравнивайте ссылку документа напрямую с измерением регистра ПломбировкаДокументов.Документ.
В реальных условиях эксплуатации базы данных нам редко требуется список абсолютно всех документов за всю историю. Чтобы запрос работал быстро и не выдавал лишней информации, необходимо добавить условия фильтрации. Выясним, какие критерии стоит учитывать:
ПриходнаяНакладная.Проведен = ИСТИНА.ПриходнаяНакладная.ПометкаУдаления = ЛОЖЬ.Обновленный запрос будет выглядеть так:
ВЫБРАТЬ
Док.Ссылка
ИЗ
Документ.ПриходнаяНакладная КАК Док
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ПломбировкаДокументов КАК Рег
ПО Док.Ссылка = Рег.Документ
ГДЕ
Рег.Документ ЕСТЬ NULL
И Док.Проведен
И НЕ Док.ПометкаУдаления
И Док.Дата > &НачалоПериода
Существует еще один способ решения задачи — использование конструкции ГДЕ Ссылка НЕ В (...) с вложенным запросом. Рассмотрим его реализацию:
ВЫБРАТЬ
ПриходнаяНакладная.Ссылка
ИЗ
Документ.ПриходнаяНакладная КАК ПриходнаяНакладная
ГДЕ
ПриходнаяНакладная.Ссылка НЕ В (
ВЫБРАТЬ
Рег.Документ
ИЗ
РегистрСведений.ПломбировкаДокументов КАК Рег
)
Проанализируем ситуацию: Данный вариант кода часто кажется более читаемым. Однако стоит помнить, что на больших таблицах (сотни тысяч и миллионы записей) классическое ЛЕВОЕ СОЕДИНЕНИЕ обычно работает эффективнее. Платформа 1С и СУБД (MS SQL, PostgreSQL) лучше оптимизируют планы запросов с соединениями, чем с вложенными подзапросами в условии ИН.
Если наш регистр ПломбировкаДокументов является периодическим, то простая связь с физической таблицей регистра может вернуть неверный результат. Например, если документ был когда-то опломбирован, затем распломбирован (создана новая запись), в физической таблице все равно останется старая запись, и LEFT JOIN не определит, что на текущий момент документ "свободен".
В этом случае нам необходимо соединяться с виртуальной таблицей СрезПоследних:
ВЫБРАТЬ
Док.Ссылка
ИЗ
Документ.ПриходнаяНакладная КАК Док
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ПломбировкаДокументов.СрезПоследних(&ТекущаяДата, ) КАК Рег
ПО Док.Ссылка = Рег.Документ
ГДЕ
Рег.Документ ЕСТЬ NULL
Для обеспечения максимального быстродействия, особенно в крупных информационных базах, разберем два ключевых правила:
Документ в регистре сведений обязательно должно быть индексируемым. Если это Измерение, оно индексируется автоматически. Если же это Реквизит, убедитесь, что в конфигураторе для него включено свойство «Индексировать». Без индекса СУБД будет вынуждена сканировать весь регистр при каждом запросе (Full Scan).ВТ_ДокументыДляПроверки), а затем соединять её с регистром. Это позволяет оптимизатору запросов СУБД построить более точный и быстрый план выполнения.Иногда в базе данных возникают ситуации, когда в регистре сведений ссылка на документ есть, но самого документа уже не существует (так называемые "битые ссылки" или "Объект не найден"). В этом случае условие ЕСТЬ NULL может сработать неожиданно. Для обеспечения чистоты данных мы рекомендуем периодически выполнять проверку на наличие пустых ссылок и корректность типов данных, используя конструкцию ЗНАЧЕНИЕ(Документ.ИмяДокумента.ПустаяСсылка).
Подведем итог: использование ЛЕВОГО СОЕДИНЕНИЯ с проверкой на NULL — это стандарт индустрии 1С для поиска отсутствующих данных. Применяя к этому методу фильтрацию по состоянию документа, индексирование и временные таблицы, вы получите надежный и производительный инструмент для контроля данных в вашей системе.