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

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

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

Использование оператора КОЛИЧЕСТВО в запросе

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

При использовании этого подхода Это делает метод крайне эффективным с точки зрения потребления трафика между сервером 1С и клиентом. Однако, если ваш запрос содержит сложные соединения (ЛЕВОЕ СОЕДИНЕНИЕ) или группировки, результат подсчета может отличаться от ожидаемого из-за дублирования строк на этапе соединения.

Рассмотрим пример кода, демонстрирующий базовое применение оператора:

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

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

"ВЫБРАТЬ

| КОЛИЧЕСТВО(Ссылка) КАК ЧислоЗаписей

|ИЗ

| Документ.РеализацияТоваровУслуг КАК Реализация

|ГДЕ

| Реализация.Дата МЕЖДУ &НачПериода И &КонПериода";

Запрос.УстановитьПараметр("НачПериода", НачПериода);

Запрос.УстановитьПараметр("КонПериода", КонПериода);

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

Выборка = Результат.Выбрать();

Если Выборка.Следующий() Тогда

Количество = Выборка.ЧислоЗаписей;

КонецЕсли;

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

⚠️ Внимание: Оператор КОЛИЧЕСТВО выполняется на стороне СУБД. Если ваш запрос содержит вызовы пользовательских функций в условиях отбора, это может резко снизить производительность, так как базе данных придется вычислить функцию для каждой строки перед подсчетом.

Подсчет через временные таблицы

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

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

  • 📊 Этап 1: Создание временной таблицы с помощью конструкции ВЫБРАТЬ.. ПОМЕСТИТЬ.
  • 🔢 Этап 2: Выполнение легкого запроса ВЫБРАТЬ КОЛИЧЕСТВО(*) из созданной таблицы.
  • 🔄 Этап 3: При необходимости, выборка самих данных для отображения пользователю из той же временной таблицы.

Пример реализации с использованием временной таблицы:

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

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

"ВЫБРАТЬ

| Реализация.Ссылка,

| Реализация.Номер

|ПОМЕСТИТЬ ВТ_Документы

|ИЗ

| Документ.РеализацияТоваровУслуг КАК Реализация

|ГДЕ

| Реализация.Проведен = ИСТИНА;

|

|ВЫБРАТЬ

| КОЛИЧЕСТВО(*) КАК Итого

|ИЗ

| ВТ_Документы";

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

// Получаем количество

КоличествоСтрок = Результат.Выгрузить()[0].Итого;

💡

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

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

Свойство Количество выборки результата

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

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

Тем не менее, в некоторых конфигурациях и при определенных драйверах СУБД это свойство работает эффективно. Оно удобно, когда вы все равно планируете обрабатывать каждую строку выборки. Вам не нужно вводить отдельную переменную-счетчик и увеличивать ее в цикле.

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

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

// Обработка строки

//..

КонецЦикла;

// После завершения цикла свойство содержит точное число пройденных строк

Сообщить("Всего обработано: " + Выборка.Количество);

💡

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

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

Оптимизация производительности при больших объемах

Когда речь заходит о миллионах записей, цена ошибки в выборе метода подсчета становится очень высокой. Запрос, который на тестовой базе с 1000 документов выполняется мгновенно, на промышленной базе может "положить" сервер на несколько минут. Ключевым фактором здесь является использование индексов и минимизация передаваемых данных.

Если ваша задача — просто показать пользователю цифру "Найдено документов: 1 500 000", нет никакой необходимости выбирать поля "Номер", "Дата", "Контрагент". Достаточно выполнить запрос только с агрегатной функцией. Это позволяет СУБД использовать покрытие индексов (Index Only Scan), не обращаясь к основным страницам данных.

Сравнение подходов по потреблению ресурсов:

Метод Нагрузка на CPU Трафик (сеть) Рекомендация
КОЛИЧЕСТВО в запросе Низкая Минимальный Лучший выбор для простого подсчета
Временная таблица Средняя Средний Для сложной логики и повторного использования
Цикл с подсчетом Высокая Огромный Избегать любой ценой
Выборка.Количество Зависит от драйвера Высокий (часто) Только если данные уже выбираются

Также стоит упомянуть о функции ЕСТЬ. Если вам нужно узнать не точное количество, а просто факт наличия записей (больше нуля или нет), используйте конструкцию ВЫБРАТЬ ЕСТЬ(..) ИЗ... Это прерывает выполнение запроса СУБД сразу после нахождения первой подходящей строки, что работает экстремально быстро.

📊 Какой метод подсчета вы используете чаще всего?
КОЛИЧЕСТВО в тексте запроса
Временные таблицы
Перебор в цикле
Свойство Выборка.Количество

Обработка пустых выборок и исключительных ситуаций

При работе с запросами всегда существует вероятность, что данные не будут найдены. Поведение системы при пустой выборке должно быть предсказуемым. Оператор КОЛИЧЕСТВО в этом плане надежен: он всегда вернет одну строку с числом 0, если условия не выполнены. Это избавляет разработчика от дополнительных проверок на пустоту результата перед обращением к полям.

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

Пример безопасной обработки:

Если Результат.Пустой() Тогда

Сообщить("Данные не найдены");

Количество = 0;

Иначе

Выборка = Результат.Выбрать();

// Дальнейшая работа

КонецЕсли;

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

Не забывайте про права доступа. Если у пользователя, от имени которого выполняется код, нет прав на чтение определенных регистров или документов, запрос может вернуть пустой результат или вызвать ошибку, в зависимости от настроек роли. Логика подсчета должна учитывать возможные ограничения RLS (Record Level Security).

Частые ошибки и рекомендации по рефакторингу

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

Еще одна ошибка — выполнение двух одинаковых запросов: одного для получения количества (через КОЛИЧЕСТВО), а второго — для получения самих данных. Это двойная нагрузка на СУБД. Правильный паттерн: использовать временную таблицу. Один раз записали данные во временное хранилище, потом сделали два легких запроса к нему: один на КОЛИЧЕСТВО, второй на выборку полей для отчета.

  • Плохо: Два раза ходить в базу с одинаковыми тяжелыми условиями.
  • Хорошо: Один раз поместить во временную таблицу, читать из нее сколько угодно раз.
  • Оптимально: Если нужно только число — использовать агрегатную функцию без выбора полей.
Секрет быстрой пагинации

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

При рефакторинге старого кода обращайте внимание на вложенные запросы. Иногда подсчет количества выносится в подзапрос, что усложняет план выполнения. Постарайтесь упростить логику: сначала отбор, потом агрегация. Чем проще текст запроса, тем выше шанс, что оптимизатор 1С и СУБД выберут верный индекс.

FAQ: Часто задаваемые вопросы

В чем разница между КОЛИЧЕСТВО(*) и КОЛИЧЕСТВО(Ссылка)?

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

Можно ли получить количество записей без выполнения запроса?

Нет, запрос выполнить необходимо, чтобы СУБД применила условия отбора (ГДЕ). Однако можно получить приблизительное количество записей во всей таблице без условий через системные представления СУБД (например, sys.dm_db_partition_stats в MSSQL), но это не будет учитывать фильтры по дате или контрагенту и требует прав администратора БД.

Почему запрос с КОЛИЧЕСТВО работает медленно?

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

Как посчитать количество уникальных значений?

Для этого используется конструкция КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Поле). Например, КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Контрагент) вернет число уникальных контрагентов в выборке, игнорируя дубликаты.