Как правильно писать условия в запросах 1С для обеспечения максимального быстродействия

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Вариант 1. Динамическое формирование текста запроса

Этот метод основан на изменении текста запроса в зависимости от того, заполнено ли значение параметра в коде 1С. Разберем пример реализации, предложенный в обсуждении:


Если ЗначениеЗаполнено(Отчет.Номенклатура) Тогда
    Запрос.УстановитьПараметр("Номенклатура", Отчет.Номенклатура);
Иначе
    // Если параметр не заполнен, удаляем условие из текста запроса
    Запрос.Текст = СтрЗаменить(Запрос.Текст, "И Номенклатуры.Ссылка = &Номенклатура", "");
КонецЕсли;

Проанализируем ситуацию: в данном случае СУБД получает «чистый» запрос. Если фильтр не нужен, его просто нет в тексте WHERE. Это позволяет оптимизатору СУБД (будь то MS SQL Server или PostgreSQL) построить максимально эффективный план выполнения.

Преимущества:

  1. SARGability (Search Argumentable): Условие максимально простое, что гарантирует использование индексов СУБД.
  2. Отсутствие лишних логических ветвлений: СУБД не тратит ресурсы на проверку условий типа «А не пустой ли это параметр?» для каждой строки таблицы.
  3. Разделение планов запросов: Для случая с фильтром и без него будут созданы разные планы выполнения, что исключает проблему «залипания» неоптимального плана (Parameter Sniffing).

Вариант 2. Универсальное условие с использованием конструкции ВЫБОР

Рассмотрим вариант, когда разработчик хочет оставить текст запроса статичным, используя внутреннюю логику языка запросов 1С:


ГДЕ
    ВЫБОР
        КОГДА &Номенклатура = ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)
            ТОГДА ИСТИНА
        ИНАЧЕ Номенклатуры.Ссылка = &Номенклатура
    КОНЕЦ

Выясним причину, почему этот вариант может быть опасен. Как справедливо отмечено в обсуждении, использование ВЫБОР в секции ГДЕ может блокировать использование индексов. СУБД часто не может заранее определить, какую часть условия использовать, и прибегает к полному сканированию таблицы (Table Scan) вместо быстрого поиска по индексу (Index Seek).

Однако стоит учитывать важный нюанс: если ВЫБОР идет как дополнительное условие после основного (которое точно использует индекс), влияние на скорость будет не таким критичным. Но для больших объемов данных это все равно остается «медленным» решением.

Вариант 3. Использование логического ИЛИ

Это один из самых популярных «ленивых» способов написания условий:


ГДЕ
    (Номенклатуры.Ссылка = &Номенклатура ИЛИ &Номенклатура = ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка))

Посмотрим на пример того, как это видит СУБД. Платформа 1С старается оптимизировать такие конструкции через SDBL (внутренний слой метаданных), и иногда ей удается передать на SQL-сервер упрощенный вариант. Но в сложных запросах с множеством соединений оптимизатор СУБД может запутаться.

Главная проблема здесь — Parameter Sniffing. Если первый раз запрос выполнится с пустой номенклатурой, СУБД построит план для получения всех записей. Если затем придет запрос с конкретной номенклатурой, СУБД может использовать тот же план (сканирование всей таблицы), что приведет к колоссальным задержкам.

Вариант 4. Конструкция В (IN)

Интересный и лаконичный вариант, предложенный участниками форума:


ГДЕ
    &Номенклатура В (Номенклатуры.Ссылка, ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка))

Хотя этот код выглядит изящно, он обладает теми же недостатками, что и вариант с ИЛИ. С точки зрения логики SQL, это превращается в перечисление условий, которые затрудняют работу оптимизатора индексов.

Почему динамический код — это профессиональный стандарт?

Проанализируем аналогию из обсуждения: представьте Александрийскую библиотеку с миллионом книг. Если вам нужно найти красные книги, и вам дали условие: «Если условие задано — ищи красные, если не задано — бери все».

В варианте со статическим запросом вы будете открывать каждую из миллиона книг и спрашивать: «А задано ли мне условие?». Это миллион лишних действий. В варианте с динамическим кодом вы либо сразу идете к стеллажу с красными книгами по индексу, либо сразу понимаете, что нужно брать всё, не задавая лишних вопросов каждой книге.

Подведем итоги и сформируем рекомендации:

  1. Для высоконагруженных систем: Всегда используйте динамическое формирование текста запроса. Это гарантирует использование индексов и чистоту SQL-кода.
  2. Для простых задач и небольших таблиц: Допускается использование конструкции с ИЛИ или ВЫБОР, если это значительно упрощает читаемость кода и не приводит к заметным задержкам.
  3. Соблюдайте правила индексации: Помните, что любое условие в ГДЕ, которое нельзя вычислить до начала сканирования таблицы, может привести к деградации производительности.
  4. Используйте конструктор запросов: Чтобы не потерять возможность редактирования запроса конструктором при использовании СтрЗаменить, применяйте специальные комментарии-маркеры в тексте запроса.

Таким образом, несмотря на то, что современные СУБД становятся умнее, ответственность за качество «входных данных» (текста запроса) лежит на разработчике 1С. Динамический текст запроса — это не просто прихоть, а способ гарантировать стабильную работу системы при росте объемов данных.

← На главную