При работе с регистрами накопления в системе 1С:Предприятие часто возникает ситуация, когда один регистр имеет десятки различных видов документов-регистраторов. Однако для решения конкретной задачи нам может потребоваться информация, порожденная только двумя или тремя специфическими типами документов. В этой статье мы подробно разберем, как правильно составить запрос, какие операторы использовать и как обеспечить максимальную производительность системы при работе с большими объемами данных.
Самый распространенный и интуитивно понятный способ — использование оператора ССЫЛКА в секции ГДЕ. Этот метод считается классическим и наиболее предпочтительным для простых задач, где количество фильтруемых типов невелико. Давайте проанализируем ситуацию, когда нам нужно получить данные только из документов ЗаказПокупателя и РеализацияТоваровУслуг.
Рассмотрим пример кода:
ВЫБРАТЬ
Продажи.Номенклатура КАК Номенклатура,
Продажи.Количество КАК Количество,
Продажи.Регистратор КАК Регистратор
ИЗ
РегистрНакопления.Продажи КАК Продажи
ГДЕ
(Продажи.Регистратор ССЫЛКА Документ.ЗаказПокупателя
ИЛИ Продажи.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг)
Почему этот метод хорош? С точки зрения СУБД (SQL Server или PostgreSQL), поле Регистратор является составным типом данных. При использовании оператора ССЫЛКА платформа 1С корректно транслирует это в SQL-запрос, который проверяет идентификатор типа (хранится в отдельной колонке или части составного поля). Поскольку поле Регистратор в физических таблицах регистров всегда индексировано, такой запрос будет работать достаточно быстро.
В более современных версиях платформы (начиная с 8.3.6) функционал работы с типами в запросах был существенно расширен. Мы можем использовать функцию ТИПЗНАЧЕНИЯ, что делает код более лаконичным, особенно если список типов документов длинный.
Разберем пример реализации:
ВЫБРАТЬ
Материалы.Номенклатура,
Материалы.Количество
ИЗ
РегистрНакопления.МатериалыНаОбъекте КАК Материалы
ГДЕ
ТИПЗНАЧЕНИЯ(Материалы.Регистратор) В (ТИП(Документ.ПоступлениеМатериала), ТИП(Документ.ВыдачаВПроизводство))
Использование конструкции В (ТИП(...), ТИП(...)) значительно повышает читаемость кода по сравнению с нагромождением условий ИЛИ. Однако важно помнить о нюансе с NULL: если вы используете левое соединение и Регистратор может принять значение NULL, функция ТИПЗНАЧЕНИЯ вернет NULL, и условие не сработает. В таких случаях безопаснее использовать ССЫЛКА.
Существует мнение, что использование ИЛИ в запросах может замедлять работу СУБД, так как оптимизатор не всегда эффективно строит план выполнения для условий по разным типам в одном поле. В высоконагруженных системах или при работе с миллионами записей стоит рассмотреть вариант разделения запроса на несколько частей.
Проанализируем такой подход:
ВЫБРАТЬ
Рег.Номенклатура,
Рег.Количество
ИЗ
РегистрНакопления.Продажи КАК Рег
ГДЕ
Рег.Регистратор ССЫЛКА Документ.ЗаказПокупателя
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Рег.Номенклатура,
Рег.Количество
ИЗ
РегистрНакопления.Продажи КАК Рег
ГДЕ
Рег.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
На первый взгляд кажется, что мы заставляем систему "бегать" по таблице дважды. Однако для СУБД это может оказаться проще: она выполнит два независимых поиска по индексу (Index Seek) и объединит результаты. Это особенно эффективно, если один вид документа составляет 1% записей регистра, а другой — 50%. Для каждого случая SQL может построить свой оптимальный план.
Если ваша задача — получить не просто записи регистра, а обороты или остатки, крайне важно накладывать фильтр внутри параметров виртуальной таблицы, а не в секции ГДЕ после выборки. Это критически влияет на скорость.
Посмотрим, как правильно настроить параметры виртуальной таблицы Обороты:
ВЫБРАТЬ
ПродажиОбороты.Номенклатура,
ПродажиОбороты.КоличествоОборот
ИЗ
РегистрНакопления.Продажи.Обороты(,, Регистратор,
Регистратор ССЫЛКА Документ.ЗаказПокупателя
ИЛИ Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг) КАК ПродажиОбороты
Обратите внимание: чтобы фильтрация по регистратору была доступна в виртуальной таблице, необходимо в параметрах указать периодичность Регистратор. В этом случае платформа отсечет ненужные данные еще на этапе формирования временной выборки на стороне сервера SQL.
Если документов-регистраторов не два, а, скажем, двадцать, то текст запроса превращается в нечитаемую "простыню". В этом случае мы рекомендуем использовать временные таблицы.
Выполним следующие шаги:
Это позволяет оптимизатору СУБД точно оценить объем данных и использовать наиболее эффективные алгоритмы соединения (например, Hash Join или Merge Join).
При выборе метода фильтрации стоит учитывать следующие технические аспекты:
1. Индексация: Поле Регистратор в физических таблицах (_AccumReg...) всегда индексировано. Но помните, что любое использование функций (кроме разрешенных платформой) в секции ГДЕ может привести к Index Scan (полному сканированию индекса), что недопустимо для больших таблиц.
2. Требования к сертификации 1С: При сдаче экзамена "1С:Специалист" важно помнить, что 1С негативно относится к выгрузке результатов запроса в ТаблицуЗначений для последующей обработки. Старайтесь выполнять всю логику фильтрации и агрегации внутри одного запроса. Это минимизирует передачу лишних данных между сервером СУБД и сервером приложений.
3. Скорость vs Читаемость: Для повседневных задач ИЛИ (метод 1) вполне достаточно. Если же вы видите, что отчет строится слишком долго, переходите к ОБЪЕДИНИТЬ ВСЕ или временным таблицам.
Выясним причину, по которой иногда IN (В) работает быстрее: СУБД может преобразовать оператор IN в список значений, который обрабатывается эффективнее, чем цепочка OR. Поэтому, если платформа позволяет использовать ТИПЗНАЧЕНИЯ(...) В (...), это будет отличным компромиссом между красотой кода и его производительностью.
Подводя итог, можно сказать: выбор метода зависит от конкретных условий. Для двух документов идеально подойдет ССЫЛКА ... ИЛИ ССЫЛКА .... Для сложных отчетов с регистрацией за длительный период — фильтрация в параметрах виртуальных таблиц. Главное — всегда проверять план выполнения запроса на реальных данных, если их объем исчисляется сотнями тысяч записей.