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