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

Эта статья не просто перечислит синтаксис оператора ВЫБРАТЬ, а раскроет внутреннюю механику работы выборки в : как формируется план выполнения, какие индексы задействуются, как влияет конфигурация СУБД (PostgreSQL, MS SQL, файловый вариант) и почему одни и те же запросы ведут себя по-разному в разных базах. Мы разберём реальные примеры кода, типичные ошибки и способы диагностики проблем — от простого ВЫБРАТЬ ПЕРВЫЕ 10 до сложных многотабличных соединений.

Базовый синтаксис: что происходит при выполнении ВЫБРАТЬ

Оператор ВЫБРАТЬ (или SELECT в англоязычной нотации) — основа любого запроса в . На первый взгляд его конструкция проста:

```sql

ВЫБРАТЬ

Поле1, Поле2

ИЗ

Справочник.Товары КАК Товары

ГДЕ

Товары.Архивный = ЛОЖЬ

```

Но что на самом деле происходит, когда этот запрос выполняется?

  • 🔹 Парсинг и валидация: платформа проверяет синтаксическую корректность запроса, преобразует его во внутреннее представление (дерево запроса).
  • 🔹 Оптимизация: анализируются условия (ГДЕ), соединения (СОЕДИНИТЬ), агрегаты (ГРУППИРОВКА) для построения оптимального плана выполнения.
  • 🔹 Генерация SQL-кода: для клиент-серверного варианта запрос транслируется в SQL-запрос конкретной СУБД (например, в SELECT для MS SQL).
  • 🔹 Выполнение: СУБД обрабатывает запрос, используя индексы, статистику и другие механизмы.
  • 🔹 Возврат результата: данные преобразуются обратно в таблицу значений .

Критичный момент: в файловом варианте 1С запрос выполняется непосредственно движком платформы без трансляции в SQL, что ограничивает возможности оптимизации. Это объясняет, почему сложные запросы в файловой базе работают медленнее, чем в клиент-серверной.

📊 Какую СУБД вы используете с 1С?
PostgreSQL
Microsoft SQL Server
Файловый вариант
IBM DB2
Другая

Как 1С преобразует запрос в SQL: примеры и подводные камни

Рассмотрим, как простой запрос на языке трансформируется в SQL для разных СУБД. Возьмём пример выборки документов за период:

```sql

ВЫБРАТЬ

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

Документ.Дата КАК Дата

ИЗ

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

ГДЕ

Документ.Дата МЕЖДУ &НачалоПериода И &КонецПериода

```

Для Microsoft SQL Server этот запрос может быть преобразован в:

```sql

SELECT

T1._Reference16 AS Ссылка,

T1._DateTime18 AS Дата

FROM

dbo._Document123 AS T1

WHERE

T1._DateTime18 BETWEEN @P1 AND @P2

```

А для PostgreSQL — немного иначе:

```sql

SELECT

"T1"."_Reference16" AS "Ссылка",

"T1"."_DateTime18" AS "Дата"

FROM

"_document123" AS "T1"

WHERE

"T1"."_DateTime18" BETWEEN $1 AND $2

```

Обратите внимание на ключевые отличия:

  • 📌 Имена таблиц и полей: в SQL они заменяются на внутренние идентификаторы (например, _Document123).
  • 📌 Параметры: вместо переменных (&НачалоПериода) подставляются параметры SQL (@P1 или $1).
  • 📌 Типы данных: дата/время в может транслироваться в разные SQL-типы (например, datetime или timestamp).
⚠️ Внимание: Если в запросе используются функции (например, НАЧАЛОПЕРИОДА()), они не всегда корректно транслируются в SQL. В некоторых случаях платформа выгружает все данные и фильтрует их уже на стороне , что критично для производительности.
💡

Чтобы увидеть сгенерированный SQL-код, включите режим отладки в конфигураторе (Сервис → Параметры → Отладка → Показывать текст запроса) или используйте инструменты профилирования СУБД.

Индексы и планы выполнения: почему запрос тормозит

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

Фактор Влияние на производительность Пример
Тип сравнения Равенство (=) использует индекс эффективнее, чем диапазоны (МЕЖДУ, >) ГДЕ Дата = &ТекущаяДата vs ГДЕ Дата >= &НачалоМесяца
Функции в условии Функции над полем (например, НАЧСТР(Наименование)) блокируют использование индекса ГДЕ ЛЕВ(Артикул, 3) = "ABC" → полное сканирование
Соединения таблиц Неправильный порядок соединений может привести к декартовым произведениям СОЕДИНИТЬ Справочник.Контрагенты ПО Умолчанию → риск полного перебора
Агрегатные функции СУММА() или КОЛИЧЕСТВО() без ГРУППИРОВКА требуют сканирования всех строк ВЫБРАТЬ СУММА(СуммаДокумента) → чтение всей таблицы

Чтобы проанализировать план выполнения запроса в MS SQL Server, используйте:

```sql

SET SHOWPLAN_TEXT ON;

-- Ваш запрос

SET SHOWPLAN_TEXT OFF;

```

Для PostgreSQL подойдёт:

```sql

EXPLAIN ANALYZE

-- Ваш запрос

```

⚠️ Внимание: В клиент-серверном варианте план выполнения формирует СУБД, а не платформа. Это означает, что для оптимизации нужно понимать особенности конкретной базы данных (например, в PostgreSQL и MS SQL могут использоваться разные стратегии индексирования).
Как просмотреть план выполнения в 1С 8.3

В конфигураторе откройте окно запроса, нажмите F5 (или кнопку "Выполнить"), затем перейдите на вкладку "План выполнения". Для детального анализа используйте инструменты СУБД (SQL Server Management Studio, pgAdmin и т.д.).

Типичные ошибки при написании запросов выборки

Даже опытные разработчики допускают ошибки, которые приводят к некорректным результатам или падению производительности. Разберём самые распространённые:

  • 🚫 Игнорирование регистра: в некоторых СУБД (например, PostgreSQL) сравнение строк учитывает регистр, а в — нет. Запрос ГДЕ Наименование = "тОвАр" может не найти запись с названием "Товар".
  • 🚫 Неявные преобразования типов: сравнение даты со строкой (ГДЕ Дата = "01.01.2023") приводит к полному сканированию таблицы.
  • 🚫 Избыточные соединения: соединение таблиц без явных условий (СОЕДИНИТЬ Справочник.Номенклатура без ПО) создаёт декартово произведение.
  • 🚫 Неправильное использование РАЗЛИЧНЫЕ: применение ВЫБРАТЬ РАЗЛИЧНЫЕ ко всем полям вместо конкретных (ВЫБРАТЬ РАЗЛИЧНЫЕ Номенклатура.Ссылка) снижает производительность.

Пример опасной конструкции:

```sql

ВЫБРАТЬ

Документ.Номенклатура КАК Номенклатура,

Документ.Количество КАК Количество

ИЗ

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

ГДЕ

Документ.Номенклатура.Наименование = "Товар 1"

```

Здесь поле Наименование не индексируется, а условие применяется к связанной таблице (Справочник.Номенклатура), что приводит к последовательному чтению всех строк документа.

Указаны все необходимые поля в ВЫБРАТЬ (без *)|

Условия в ГДЕ используют индексируемые поля|

Нет функций над полями в условиях (ЛЕВ(), НАЧСТР())|

Соединения таблиц имеют явные условия (ПО)|

Для больших выборок ограничен результат (ПЕРВЫЕ 1000)

-->

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

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

  1. Используйте явные соединения:

    Заменяйте СОЕДИНИТЬ без условий на явные связи:

    СОЕДИНИТЬ Справочник.Контрагенты КАК Контрагенты
    

    ПО Документ.Контрагент = Контрагенты.Ссылка

  2. Ограничивайте результат:

    Для отладочных целей или предварительного просмотра используйте ПЕРВЫЕ N:

    ВЫБРАТЬ ПЕРВЫЕ 100
  3. Избегайте подзапросов в условиях:

    Подзапрос в ГДЕ часто приводит к полному сканированию. Заменяйте его соединением:

    Плохо: ГДЕ Номенклатура В (ВЫБРАТЬ Ссылка ИЗ Справочник.АкционныеТовары)

    Хорошо: СОЕДИНИТЬ Справочник.АкционныеТовары ПО Номенклатура.Ссылка = АкционныеТовары.Ссылка

  4. Анализируйте статистику:

    В MS SQL Server обновите статистику командой EXEC sp_updatestats, в PostgreSQLANALYZE.

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

💡

Самая частая причина медленных запросов — отсутствие индексов по полям, используемым в условиях ГДЕ и СОЕДИНИТЬ. Всегда проверяйте, есть ли индексы на ключевых полях (ссылки, даты, часто фильтруемые реквизиты).

Особенности выборки в разных версиях 1С

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

Версия платформы Особенности выборки Пример изменений
1С 7.7 Отсутствует язык запросов в современном виде. Выборка реализуется через объекты или внешние обработки. Использование методов Выбрать(), НайтиПоНаименованию().
1С 8.0–8.1 Появление языка запросов, но с ограниченными возможностями (нет ОБЪЕДИНИТЬ, ИТОГИ). Отсутствует поддержка ВРЕМЕННЫЕ ТАБЛИЦЫ.
1С 8.2 Добавлены временные таблицы, расширены возможности соединений. Появился ПАКЕТНЫЕ ЗАПРОСЫ. ВЫБРАТЬ ... В ВРЕМЕННУЮ ТАБЛИЦУ.
1С 8.3 Улучшена оптимизация запросов, добавлены новые функции (ВЫРАЗИТЬ, РАЗРЕШЕННЫЕ). ВЫБРАТЬ РАЗРЕШЕННЫЕ Номенклатура.Ссылка КАК Ссылка.
1С 8.3.20+ Поддержка JSON-функций, улучшенная работа с большими данными. ВЫБРАТЬ JSONЗНАЧЕНИЕ(Данные, '$.Сумма').

Важно учитывать, что в старых версиях (до 8.3.10) некоторые конструкции могут работать некорректно. Например, в 1С 8.2 запрос с ОБЪЕДИНИТЬ и ГРУППИРОВКА мог возвращать неверные итоги.

⚠️ Внимание: При переносе кода между версиями всегда тестируйте запросы на целевой платформе. Например, функция ВЫРАЗИТЬ(), появившаяся в 8.3.10, вызовет ошибку в более ранних релизах.

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

Для сложных операций с данными в предусмотрены пакетные запросы и временные таблицы. Они позволяют:

  • 🔄 Разбивать большие выборки на части (пагинация).
  • 🗃️ Сохранять промежуточные результаты для повторного использования.
  • 🔗 Упрощать сложные соединения за счёт предварительной агрегации данных.

Пример использования временной таблицы для ускорения отчёта:

```sql

// Создаём временную таблицу с агрегированными данными

ВЫБРАТЬ

Документ.Контрагент КАК Контрагент,

СУММА(Документ.СуммаДокумента) КАК Итого

ИЗ

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

ГДЕ

Документ.Дата МЕЖДУ &НачалоПериода И &КонецПериода

СГРУППИРОВАТЬ ПО

Документ.Контрагент

ПОМЕСТИТЬ ВТ_ИтогиПоКонтрагентам;

// Используем временную таблицу в основном запросе

ВЫБРАТЬ

Контрагенты.Наименование КАК Контрагент,

Итоги.Итого КАК Сумма

ИЗ

ВТ_ИтогиПоКонтрагентам КАК Итоги

ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Контрагенты КАК Контрагенты

ПО Итоги.Контрагент = Контрагенты.Ссылка

УПОРЯДОЧИТЬ ПО

Сумма УБЫВ

```

Пакетные запросы полезны, когда нужно выполнить несколько связанных операций в одной транзакции:

```sql

НАЧАТЬ ТРАНЗАКЦИЮ;

ВЫПОЛНИТЬ ЗАПРОС

"УДАЛИТЬ ИЗ ВТ_СтарыеДанные";

ВЫПОЛНИТЬ ЗАПРОС

"ВСТАВИТЬ В ВТ_НовыеДанные (Поле1, Поле2)

ВЫБРАТЬ ПолеА, ПолеБ ИЗ ИсточникДанных";

ЗАФИКСИРОВАТЬ ТРАНЗАКЦИЮ;

```

Ограничение: временные таблицы существуют только в рамках одного сеанса. После закрытия соединения или завершения транзакции (если не зафиксирована) данные будут утеряны.

FAQ: Частые вопросы о выборке в 1С

Почему запрос возвращает дублирующиеся строки?

Дубли возникают, если:

  • В запросе нет условия ГРУППИРОВКА для агрегатных функций (СУММА, КОЛИЧЕСТВО).
  • Используются соединения ПОЛНОЕ или ЛЕВОЕ без фильтрации NULL-значений.
  • В выборке участвуют таблицы с отношением "один-ко-многим" без явной агрегации.

Решение: добавьте РАЗЛИЧНЫЕ или ГРУППИРОВКА, проверьте логику соединений.

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

Способы оптимизации:

  1. Разбейте запрос на несколько этапов с использованием временных таблиц.
  2. Замените соединения ПОЛНОЕ на ЛЕВОЕ или ВНУТРЕННЕЕ, если это возможно.
  3. Добавьте индексы на поля, используемые в условиях ГДЕ и СОЕДИНИТЬ.
  4. Используйте ПЕРВЫЕ N для тестирования и отладки.
Можно ли в запросе 1С использовать подзапросы в разделе ВЫБРАТЬ?

Да, но с оговорками:

  • Подзапросы в ВЫБРАТЬ должны возвращать одно значение (скалярные подзапросы).
  • Пример: ВЫБРАТЬ (ВЫБРАТЬ МАКСИМУМ(Дата) ИЗ Документ.ЗаказыКлиентов) КАК ПоследняяДата.
  • Сложные подзапросы могут снизить производительность — лучше заменить их соединениями.
Почему запрос работает быстро в конфигураторе, но медленно в пользовательском режиме?

Возможные причины:

  • В конфигураторе используется кэш метаданных, а в пользовательском режиме — нет.
  • Разные права доступа: ограничения РЛС могут приводить к дополнительной фильтрации.
  • В пользовательском режиме запрос выполняется в транзакции с другими операциями, что блокирует таблицы.
  • На сервере 1С включены дополнительные проверки (например, аудит изменений).

Решение: проверьте план выполнения запроса в обоих режимах, анализируйте журнал регистрации.

Как выбрать данные из виртуальной таблицы регистров?

Виртуальные таблицы регистров (например, РегистрНакопления.ОстаткиТоваров) позволяют получать остатки, обороты и другие агрегированные данные без ручных расчётов. Пример:

ВЫБРАТЬ

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

ОстаткиТоваров.КоличествоОстаток КАК Остаток

ИЗ

РегистрНакопления.ОстаткиТоваров КАК ОстаткиТоваров

ГДЕ

ОстаткиТоваров.Номенклатура В (&СписокНоменклатуры)

И ОстаткиТоваров.Дата = &ТекущаяДата

Особенности:

  • Виртуальные таблицы всегда возвращают актуальные данные на указанную дату.
  • Для ускорения используйте отбор по ключевым полям (номенклатура, склад).
  • Избегайте выборки всех полей (*) — указывайте только необходимые.