Разработка и Конфигурация · 11 мин
Как узнать количество строк в запросе 1С
Способы узнать количество строк в запросе 1С: метод Выгрузить().Количество(), функция КОЛИЧЕСТВО в запросе, обход выборки. Примеры кода, ошибки и советы.
Подсчёт строк результата запроса — одна из самых частых задач при разработке на платформе 1С:Предприятие. Она возникает при проверке наличия данных перед обработкой, при выводе статистики в отчётах, при контроле дублей и при построении условной логики: «если записей нет — показать сообщение, если есть — продолжить».
В языке запросов 1С и во встроенном языке есть несколько способов получить количество строк, и у каждого своя цена по производительности. Метод Выгрузить().Количество() загружает весь результат в память, агрегатная функция КОЛИЧЕСТВО считает на стороне СУБД, а обход выборки позволяет совместить подсчёт с обработкой данных. Выбор зависит от того, нужны ли вам сами данные или только их число.
Ниже разобраны все рабочие подходы с примерами кода, сравнение их производительности, типичные ошибки и способы проверить корректность результата.
Основные способы подсчёта строк и когда их применять
Существует четыре практических подхода. Первый — агрегатная функция КОЛИЧЕСТВО прямо в тексте запроса: СУБД возвращает одно число, и данные строк по сети не передаются. Второй — метод Количество() у таблицы значений, полученной через Выгрузить(). Третий — цикл по выборке со счётчиком. Четвёртый — проверка Пустой(), когда нужно знать только факт наличия данных, а не точное число.
Ключевой критерий выбора — нужны ли вам сами данные. Если требуется только число (например, для проверки «есть ли дубли контрагента»), выгружать таблицу значений расточительно: на больших выборках это лишняя память и время. Если данные всё равно будут обрабатываться, подсчёт через Выгрузить().Количество() обходится без дополнительного обращения к базе.
Сравнение вариантов
Оптимально, когда нужно только число. Минимальный трафик и память, подсчёт на стороне СУБД.
Подходит, когда результат и так нужен в виде таблицы значений. Не требует повторного запроса.
Уместен, когда подсчёт совмещается с обработкой каждой строки. Не даёт число до завершения цикла.
Только факт наличия/отсутствия строк. Не возвращает точное количество.
Подсчёт через КОЛИЧЕСТВО в тексте запроса
Агрегатная функция КОЛИЧЕСТВО — самый эффективный способ, когда нужно только число строк. Запрос возвращает одну строку с одним полем, и весь объём данных остаётся на стороне СУБД.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| КОЛИЧЕСТВО(*) КАК КоличествоСтрок
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| НЕ Номенклатура.ПометкаУдаления";
Выборка = Запрос.Выполнить().Выбрать();
Выборка.Следующий();
КоличествоСтрок = Выборка.КоличествоСтрок;Обратите внимание на различие вариантов функции. КОЛИЧЕСТВО(*) считает все строки выборки. КОЛИЧЕСТВО(Поле) считает строки, где указанное поле не равно NULL — это важно для левых соединений, где часть полей может быть пустой. КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Поле) считает количество уникальных значений, что удобно для подсчёта разных контрагентов в таблице заказов.
Если агрегатная функция используется без группировки, запрос всегда вернёт ровно одну строку, даже когда исходная таблица пуста — в этом случае значение будет 0. Это избавляет от проверки на пустую выборку перед чтением результата.
Подсчёт через Выгрузить().Количество()
Когда результат запроса нужен для дальнейшей работы — вывода в табличный документ, обхода в цикле, передачи в другую процедуру — логично выгрузить его в таблицу значений и узнать количество строк её методом Количество().
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Товары.Номенклатура КАК Номенклатура,
| Товары.Количество КАК Количество
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК Товары
|ГДЕ
| Товары.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", ДокументСсылка);
ТаблицаРезультата = Запрос.Выполнить().Выгрузить();
КоличествоСтрок = ТаблицаРезультата.Количество();Этот способ не требует повторного обращения к базе данных: число берётся из уже материализованной таблицы. Но помните о цене выгрузки — весь результат целиком копируется в оперативную память. Для табличных частей документов и типовых справочников это не проблема, а вот выборка из сотен тысяч строк регистра накопления может заметно нагрузить сервер.
Если данные нужны не как таблица, а только для последовательного чтения, альтернатива — обход выборки, который разобран ниже. Он не хранит все строки в памяти одновременно.
Подсчёт при обходе выборки
Третий вариант — считать строки вручную в цикле Пока Выборка.Следующий() Цикл. Сам по себе такой подсчёт редко оправдан: это самый медленный способ узнать только число. Но он естественен, когда подсчёт совмещается с основной обработкой данных.
Выборка = Запрос.Выполнить().Выбрать();
КоличествоСтрок = 0;
Пока Выборка.Следующий() Цикл
КоличествоСтрок = КоличествоСтрок + 1;
// основная обработка строки
КонецЦикла;Ограничение метода очевидно: итоговое число становится известно только после завершения цикла. Если количество нужно заранее — например, чтобы показать пользователю прогресс «обработано 10 из 5000» — придётся либо выполнять отдельный запрос с КОЛИЧЕСТВО, либо сначала выгружать данные в таблицу значений.
Дополнительный плюс выборки — возможность использовать метод Выборка.Количество() без обхода: он возвращает число строк в выборке. Однако на практике для получения этого числа платформа всё равно материализует результат, поэтому выигрыша в памяти по сравнению с Выгрузить() обычно нет.
Проверка наличия строк без точного подсчёта
Очень часто точное число строк не нужно — требуется лишь ответить на вопрос «есть ли данные». Классический пример: перед созданием элемента справочника проверить, нет ли уже записи с таким наименованием. Для этого у объекта РезультатЗапроса есть метод Пустой().
РезультатЗапроса = Запрос.Выполнить();
Если РезультатЗапроса.Пустой() Тогда
Сообщить("Данные не найдены");
Иначе
// данные есть, можно выбирать
КонецЕсли;Дополнительная оптимизация — ограничить выборку одной строкой через ВЫБРАТЬ ПЕРВЫЕ 1. Тогда СУБД остановит поиск при первой же найденной записи, а не будет сканировать все подходящие строки. На больших таблицах разница по времени заметна.
- 1Сформируйте запрос с ВЫБРАТЬ ПЕРВЫЕ 1 и нужным отбором
- 2Выполните запрос и сохраните результат в переменную
- 3Вызовите РезультатЗапроса.Пустой()
- 4Если результат Истина — данных нет, выполните ветку обработки отсутствия
- 5Если Ложь — данные есть, при необходимости получите выборку
Производительность и работа с большими таблицами
Главное правило: не выгружайте данные, которые не нужны. Запрос с КОЛИЧЕСТВО(*) и запрос с выборкой всех полей с последующим Количество() дают одинаковое число, но первый передаёт по сети одну строку, а второй — всю таблицу. На регистрах с миллионами записей разница составляет секунды и даже десятки секунд.
Учитывайте и отборы. Подсчёт по индексированному полю (например, по ссылке на документ) выполняется быстро, а подсчёт с условием по неиндексированному реквизиту или с функцией в условии (например, ПОДСТРОКА(...) в отборе) заставляет СУБД сканировать таблицу целиком. Если подсчёт тормозит, проверьте план запроса и состав индексов.
В клиент-серверном варианте тяжёлые запросы с подсчётом лучше выполнять в серверных процедурах. Вызов запроса с тонкого клиента без контекста сервера приведёт к передаче данных не туда, где они обрабатываются, и к лишним обращениям.
Типичные ошибки при подсчёте строк
Первая частая ошибка — чтение поля выборки без вызова Следующий(). После выполнения запроса курсор выборки стоит перед первой строкой, и обращение к Выборка.КоличествоСтрок без позиционирования вернёт неопределённое поведение или пустое значение. Всегда вызывайте Следующий() перед чтением полей.
Вторая ошибка — путаница между КОЛИЧЕСТВО(*) и КОЛИЧЕСТВО(Поле) в запросах с соединениями. Если левое соединение не нашло пару, поля правой таблицы содержат NULL, и подсчёт по такому полю занижает результат. Проверяйте, что именно вы считаете: строки левой таблицы или непустые связи.
Третья ошибка — двойное выполнение одного и того же запроса: сначала с КОЛИЧЕСТВО для получения числа, потом полный для получения данных. Это удваивает нагрузку на СУБД. Если нужны и число, и данные — выгрузите результат один раз и используйте Количество() у таблицы значений.
Проверка корректности результата
После написания кода убедитесь, что число соответствует реальному содержимому базы. Самый простой способ — выполнить тот же запрос в консоли запросов и сравнить количество строк в таблице результата с тем, что вернул ваш код.
Для запросов с группировкой помните: КОЛИЧЕСТВО вернёт число строк в каждой группе, а не общее количество. Если нужна сумма по всем группам, добавьте итоги через ИТОГИ или выполните подсчёт без группировки.
Как проверить результат
Число из кода совпадает с количеством строк в консоли при тех же параметрах
Числа расходятся — проверьте параметры, отборы и соединения
КОЛИЧЕСТВО(<em>) возвращает 0, Пустой() возвращает Истина
Код падает с ошибкой при отсутствии данных — нет обработки пустого результата
КОЛИЧЕСТВО(</em>) считает все строки левой таблицы
Используется КОЛИЧЕСТВО(ПолеПравойТаблицы) и итог меньше ожидаемого
Частые вопросы
Чем Пустой() отличается от сравнения Количество() с нулём?
Метод Пустой() отвечает только на вопрос «есть ли хотя бы одна строка» и в сочетании с ВЫБРАТЬ ПЕРВЫЕ 1 позволяет СУБД остановиться на первой найденной записи. Сравнение Количество() с нулём требует знать точное число, что на больших таблицах дороже. Если точное количество не нужно, используйте Пустой().
Как посчитать количество строк табличной части документа?
Если объект документа уже прочитан, запрос не нужен: обратитесь к табличной части напрямую — ДокументОбъект.Товары.Количество(). Запрос к табличной части оправдан только когда документ не загружен в память и нужны данные сразу нескольких документов.
Можно ли узнать количество строк, не выполняя запрос повторно?
Да. Если результат уже выгружен в таблицу значений, её метод Количество() вернёт число строк без обращения к базе. Если работаете с выборкой, метод Выборка.Количество() также возвращает число строк результата без повторного выполнения запроса.
Почему КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Поле) работает медленно?
Подсчёт различных значений требует от СУБД устранения дублей — фактически сортировки или хеширования всего набора значений. На больших таблицах это ресурсоёмкая операция. По возможности ограничивайте выборку отбором по периоду или другим индексированным полям.
Как получить количество строк в запросе с группировкой?
При группировке КОЛИЧЕСТВО считается внутри каждой группы, и запрос возвращает по строке на группу. Чтобы узнать общее число строк исходных данных, уберите группировку или добавьте ИТОГИ СУММА(КоличествоСтрок) ПО ОБЩИЕ — тогда общий итог будет в строке с пустым значением поля группировки.
Что важно запомнить
Для получения только числа строк используйте КОЛИЧЕСТВО(<em>) в тексте запроса — это самый быстрый способ. Если данные нужны для обработки, выгрузите результат один раз и возьмите Количество() у таблицы значений. Для проверки наличия данных достаточно ВЫБРАТЬ ПЕРВЫЕ 1 и метода Пустой(). Перед чтением полей выборки всегда вызывайте Следующий(), а в запросах с соединениями осознанно выбирайте между КОЛИЧЕСТВО(</em>) и КОЛИЧЕСТВО(Поле).