Работа с данными в конфигурациях на платформе 1С:Предприятие 8 невозможна без манипуляций со ссылками на объекты. Справочники являются основным хранилищем нормативно-справочной информации, и задача перебора их элементов возникает у разработчика постоянно. Будь то формирование сложного отчета, пакетное обновление реквизитов или интеграция с внешними системами, выбор правильного метода итерации напрямую влияет на скорость работы программы.

Существует несколько фундаментально разных подходов к решению этой задачи: от простого использования встроенного механизма выборки до написания сложных запросов на языке 1СКД. Неправильный выбор инструмента может привести к критическому замедлению системы при увеличении объема базы данных. В этой статье мы детально разберем каждый метод, его преимущества и подводные камни, чтобы вы могли писать эффективный код.

Использование объекта ВыборкаСправочника

Самый простой и интуитивно понятный способ получить доступ ко всем записям — это создание объекта ВыборкаСправочника. Этот метод идеально подходит для небольших справочников или ситуаций, когда требуется обработать каждый элемент без сложных условий фильтрации. Код получается лаконичным и легко читаемым даже для начинающих программистов.

Для инициализации выборки достаточно вызвать метод Выбрать() у объекта справочника. Важно понимать, что в момент вызова этого метода формируется курсор базы данных, который начинает последовательно проходить по всем узлам. Если в процессе обработки вы будете менять структуру справочника, это может привести к непредсказуемому поведению курсора.

Вот классический пример реализации такого подхода:

СправочникОбъект = Справочники.Номенклатура;

Выборка = СправочникОбъект.Выбрать();

Пока Выборка.Следующий() Цикл

// Обработка текущего элемента

Сообщение = "Обработан элемент: " + Выборка.Наименование;

КонецЦикла;

Однако у этого метода есть существенный недостаток — производительность. При работе с большими объемами данных (десятки или сотни тысяч записей) использование простой выборки может занять значительное время. Это связано с тем, что платформе приходится поддерживать состояние курсора и последовательно загружать каждый объект в память.

⚠️ Внимание: Никогда не используйте метод Выбрать() внутри циклов или в высоконагруженных регламентных заданиях без предварительной оценки объема данных. Это частая причина зависания сервера 1С в часы пик.

Если вам нужно выбрать только активные элементы или отфильтровать их по какому-то простому признаку, лучше сразу использовать параметры выборки. Это позволит отсеять лишние записи еще на уровне СУБД, не загружая их в память приложения.

💡

Используйте метод Выборка.Следующий() вместо перебора по индексу — это гарантирует корректную работу с иерархическими справочниками и группами.

Оптимизация через язык запросов 1С

Для профессиональной разработки стандартом де-факто является использование языка запросов. Этот подход дает максимальную гибкость и позволяет переложить основную работу по фильтрации и сортировке на сторону сервера баз данных (MS SQL, PostgreSQL или Oracle). Запрос выбирает только нужные поля, что снижает нагрузку на сеть и оперативную память.

Основное преимущество запросов заключается в возможностиjoins (соединений) и агрегации данных еще до того, как они попадут в код 1С. Вы можете сразу получить выборку, содержащую ссылки на справочники и связанные с ними регистры сведений. Это избавляет от необходимости делать дополнительные обращения к базе внутри цикла обработки.

Типичная структура запроса для перебора элементов выглядит следующим образом:

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Номенклатура.Ссылка КАК Ссылка,

| Номенклатура.Наименование КАК Наименование,

| Номенклатура.Артикул КАК Артикул

|ИЗ

| Справочник.Номенклатура КАК Номенклатура

|ГДЕ

| Номенклатура.ЭтоГруппа = ЛОЖЬ";

Результат = Запрос.Выполнить();

ВыборкаДетальныеЗаписи = Результат.Выбрать();

Пока ВыборкаДетальныеЗаписи.Следующий() Цикл

// Работа с полями выборки

КонецЦикла;

Важно отметить разницу между получением ссылки и получением объекта. В запросе мы чаще всего выбираем поле Ссылка, которая является легковесным объектом. Если внутри цикла вам потребуется изменить реквизиты элемента, ссылку нужно будет превратить в объект справочника методом ПолучитьОбъект(), что является дорогостоящей операцией.

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

📊 Какой метод перебора вы используете чаще всего?
Простая выборка (Выбрать)
Язык запросов
Пакетное чтение
Конструктор запросов

Работа с иерархией и обход дерева

Многие справочники в 1С имеют иерархическую структуру, где элементы вложены в группы. Стандартная выборка проходит по всем элементам "плоским" списком, игнорируя уровень вложенности. Однако иногда критически важно соблюдать порядок обхода: сначала родитель, потом дети, или наоборот.

Для решения таких задач используется свойство ИспользоватьИерархию объекта выборки. Установив его в значение Истина, вы заставляете курсор двигаться по дереву узлов. При этом доступен специальный метод ТекущийУровеньИерархии(), который показывает глубину вложенности текущего элемента.

Рассмотрим пример обхода дерева с учетом уровней:

  • 🌳 Уровень 0: Корневые группы справочника.
  • 📂 Уровень 1: Элементы или подгруппы, находящиеся непосредственно в корне.
  • 📁 Уровень N: Вложенные элементы, глубина которых зависит от структуры.

При включенной иерархии метод Следующий() будет возвращать элементы в порядке их физического расположения в дереве. Это удобно для формирования печатных форм или отчетов, где важна группировка "от общего к частному". Но помните, что такой обход может быть медленнее плоского, так как СУБД должна выстраивать порядок выборки согласно структуре дерева.

⚠️ Внимание: При изменении структуры справочника (перемещение элементов между группами) во время обхода с включенной иерархией поведение выборки становится неопределенным. Рекомендуется сначала собрать список ссылок, а затем обрабатывать их.

Если вам нужно обработать только элементы определенной ветки, не проходя по всему справочнику, используйте метод ВыбратьИерархически() с указанием родительского элемента. Это существенно сократит область поиска и ускорит выполнение кода.

Пакетное чтение и производительность

Когда объем данных исчисляется миллионами записей, даже оптимизированный запрос может работать медленно из-за накладных расходов на передачу данных между сервером 1С и клиентом, либо между разными серверами в кластере. В таких случаях на помощь приходит механизм Пакетного чтения.

Суть метода заключается в том, что данные выбираются не по одной записи, а большими блоками (пакетами). Это позволяет минимизировать количество сетевых обращений и более эффективно использовать буферы памяти. Пакетное чтение особенно актуально для фоновых заданий, выгрузок данных и конвертации информации.

Для реализации этого подхода используется объект ЧтениеДанных. Он работает быстрее стандартной выборки, но имеет ограничение: вы получаете данные только для чтения. Изменять объекты напрямую через этот механизм нельзя, нужно сначала получить ссылку, а затем отдельным вызовом записать изменения.

Метод Скорость Возможность записи Сложность реализации
ВыборкаСправочника Низкая Да (через ПолучениеОбъекта) Низкая
Запрос + Выборка Средняя/Высокая Да (через ПолучениеОбъекта) Средняя
ЧтениеДанных Очень высокая Нет (только чтение) Высокая

Настройка размера пакета осуществляется через свойство РазмерПакета. Экспериментальным путем можно подобрать оптимальное значение для вашей инфраструктуры. Слишком маленький пакет не даст выигрыша в скорости, а слишком большой может привести к перерасходу оперативной памяти сервера.

Тонкости настройки ЧтенияДанных

Для максимального ускорения отключайте контроль целостности ссылок и не запрашивайте лишние реквизиты. Указывайте в полях чтения только те данные, которые реально используются в алгоритме.

Обработка помеченных на удаление объектов

Одной из частых задач администрирования и сопровождения 1С является очистка базы от "мусора". Элементы справочников, помеченные на удаление, по умолчанию скрываются из большинства выборок и интерфейсов. Однако для их физического удаления или восстановления необходимо явно перебрать именно эти записи.

Стандартная выборка игнорирует помеченные объекты. Чтобы получить к ним доступ, необходимо установить специальное свойство ПометкаУдаления в режим ТолькоПомеченныеНаУдаление или Все. Это позволяет отделить "живые" данные от тех, что готовы к утилизации.

Пример кода для поиска таких элементов:

Выборка = Справочники.Контрагенты.Выбрать();

Выборка.ПометкаУдаления = РежимПометкиУдаленияОбъектов.ТолькоПомеченныеНаУдаление;

Пока Выборка.Следующий() Цикл

// Логика восстановления или окончательного удаления

КонецЦикла;

Важно различать логическое удаление (пометка) и физическое удаление. Перебор помеченных объектов не удаляет их автоматически. Для физической очистки используется механизм удаления помеченных объектов, который также можно запустить программно, но это требует прав администратора и блокировки работы пользователей.

⚠️ Внимание: Интерфейсы и состав доступных полей могут меняться в разных версиях платформы 1С. Всегда сверяйте актуальные свойства объектов в синтаксис-помощнике вашей конкретной конфигурации перед написанием кода работы с удалением.

Частые ошибки и антипаттерны

Даже опытные разработчики иногда допускают ошибки при организации циклов перебора. Самая распространенная проблема — модификация коллекции во время итерации. Если вы удаляете элемент справочника или меняете его владельца (родителя) внутри цикла Пока Выборка.Следующий(), вы рискуете сбить курсор выборки.

Это может привести к тому, что некоторые элементы будут пропущены, а обработка зациклится на одной записи. Правильный подход в таких случаях — сначала собрать все ссылки, требующие изменения, в массив или временную таблицу, а уже потом, после завершения выборки, обработать этот список.

Еще один антипаттерн — выполнение запросов внутри цикла. Никогда не делайте так:

  • Плохо: Внутри цикла выборки элементов номенклатуры делать новый запрос к регистру цен для каждого товара.
  • Хорошо: Сделать один общий запрос с соединением (JOIN), который сразу вернет товары и их цены.

Такой подход, называемый "N+1 запрос", убивает производительность системы. Вместо одной операции база данных вынуждена выполнять тысячи, что создает огромную нагрузку на диск и процессор сервера.

💡

Золотое правило оптимизации: минимизируйте количество обращений к базе данных. Один сложный запрос всегда лучше, чем тысяча простых внутри цикла.

FAQ: Вопросы и ответы

Как перебрать только элементы без групп?

Для этого в запросе добавьте условие ГДЕ Справочник.ЭтоГруппа = ЛОЖЬ. Если используете простую выборку, проверяйте свойство Выборка.ЭтоГруппа внутри цикла и пропускайте итерацию, если оно истинно.

Можно ли изменять реквизиты элемента прямо в выборке?

Нет, объект выборки доступен только для чтения. Чтобы изменить данные, нужно получить объект справочника по ссылке: Объект = Выборка.Ссылка.ПолучитьОбъект(), внести изменения и вызвать Объект.Записать().

Что делать, если выборка работает слишком медленно?

Попробуйте перейти на язык запросов с отбором нужных полей. Если это не помогает, используйте механизм ЧтениеДанных с настройкой размера пакета. Также проверьте наличие индексов в базе данных для полей, по которым идет отбор.

Как получить количество элементов без полного перебора?

Не используйте цикл для подсчета! В запросе используйте агрегатную функцию КОЛИЧЕСТВО(*). Для простой выборки есть свойство Количество(), но оно также может требовать прохода по данным в некоторых реализациях, поэтому запрос предпочтительнее.