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

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

В практике разработчика 1С часто возникает ситуация, когда два практически идентичных запроса показывают колоссальную разницу в производительности. В нашем случае один запрос выполняется за 0,022 секунды, а второй — за 3,425 секунды. При этом структура запросов совпадает, а разница заключается лишь в поле, по которому строится условие ГДЕ. Проанализируем эту ситуацию, выясним скрытые причины такого поведения системы и найдем способы оптимизации.

Анализ исходной ситуации

Рассмотрим два запроса к документу ЗаказКлиента. Оба запроса ограничивают выборку по периоду ДатаОтгрузки и статусу Проведен.

Запрос №1 (быстрый):


ВЫБРАТЬ
    ЗаказКлиента.Ссылка КАК Ссылка,
    ЗаказКлиента.СуммаДокумента КАК СуммаДокумента,
    ЗаказКлиента.Склад КАК Склад,
    ЗаказКлиента.ДатаОтгрузки КАК ДатаОтгрузки
ИЗ
    Документ.ЗаказКлиента КАК ЗаказКлиента
ГДЕ
    ЗаказКлиента.ДатаОтгрузки >= ДАТАВРЕМЯ(2023, 1, 1)
    И ЗаказКлиента.ДатаОтгрузки <= ДАТАВРЕМЯ(2023, 12, 31)
    И ЗаказКлиента.Партнер = &Партнер
    И ЗаказКлиента.Проведен = ИСТИНА

Запрос №2 (медленный):


ВЫБРАТЬ
    ЗаказКлиента.Ссылка КАК Ссылка,
    ЗаказКлиента.СуммаДокумента КАК СуммаДокумента,
    ЗаказКлиента.Склад КАК Склад,
    ЗаказКлиента.ДатаОтгрузки КАК ДатаОтгрузки
ИЗ
    Документ.ЗаказКлиента КАК ЗаказКлиента
ГДЕ
    ЗаказКлиента.ДатаОтгрузки >= ДАТАВРЕМЯ(2023, 1, 1)
    И ЗаказКлиента.ДатаОтгрузки <= ДАТАВРЕМЯ(2023, 12, 31)
    И ЗаказКлиента.Грузополучатель = &Грузополучатель
    И ЗаказКлиента.Проведен = ИСТИНА

Несмотря на схожесть, второй запрос работает в 150 раз медленнее. Разберем по шагам, какие факторы влияют на такую разницу.

Причина 1: Скрытые индексы через Критерии отбора

Первым делом проанализируем метаданные. Часто разработчики смотрят только на свойство Индексировать у конкретного реквизита в конфигураторе. Если там установлено значение "Не индексировать", это еще не означает, что индекса в базе данных не существует.

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

В то же время реквизит Грузополучатель может не входить ни в один критерий отбора и не иметь явной индексации. В этом случае системе приходится выполнять Table Scan (полное сканирование таблицы). Для базы в 50 000 документов в файловом режиме это занимает значительное время, так как программе нужно прочитать каждую запись с диска, чтобы проверить условие.

Причина 2: Особенности файловой базы данных

Проанализируем влияние файлового режима (формат .1CD). В отличие от клиент-серверного варианта под управлением MS SQL Server или PostgreSQL, файловый движок 1С имеет менее эффективный оптимизатор запросов и кэширование. Если данные по партнерам часто используются в других задачах системы, они могут "осесть" в оперативной памяти (кэше). Данные по грузополучателям, если к ним обращаются редко, считываются непосредственно с жесткого диска, что добавляет задержки ввода-вывода.

Причина 3: Работа с составными типами данных

Посмотрим на тип данных реквизита. Если Грузополучатель имеет составной тип (например, СправочникСсылка.Контрагенты и СправочникСсылка.Партнеры), то в физической таблице базы данных это поле представлено несколькими колонками (одна для типа, другая для ссылки). Запросы к таким полям без уточнения типа работают медленнее.

Рассмотрим, как можно оптимизировать такой запрос с помощью функции ВЫРАЗИТЬ. Это подскажет системе, с какой конкретно таблицей нужно сопоставлять данные, исключая лишние проверки:


ГДЕ
    ЗаказКлиента.ДатаОтгрузки МЕЖДУ &ДатаНачала И &ДатаКонца
    И ВЫРАЗИТЬ(ЗаказКлиента.Грузополучатель КАК Справочник.Контрагенты) = &Грузополучатель
    И ЗаказКлиента.Проведен = ИСТИНА

Как проверить наличие индексов программно?

Чтобы точно узнать, какие индексы созданы в вашей базе (включая неявные), выполним следующий метод:

Воспользуемся функцией ПолучитьСтруктуруХраненияБазыДанных(). Она вернет таблицу с описанием всех таблиц и индексов на уровне СУБД. Проанализировав колонку ИмяТаблицыХранения и связанные с ней индексы для документа ЗаказКлиента, мы увидим реальную картину.

Способы решения проблемы

На основе нашего исследования выделим три основных способа ускорения запроса:

  1. Явная индексация: Самый простой и эффективный метод. В конфигураторе для реквизита Грузополучатель установим свойство Индексировать в значение "Индексировать". Это создаст индекс и сравняет скорость выполнения второго запроса с первым.
  2. Индексация с дополнительным упорядочиванием: Если мы часто делаем отборы по грузополучателю в связке с датой (как в нашем примере), стоит выбрать вариант "Индексировать с дополнительным упорядочиванием". Это создаст составной индекс [Грузополучатель + Дата], что позволит системе максимально быстро находить документы за конкретный период по конкретному получателю.
  3. Использование временных таблиц: Если по каким-то причинам изменять метаданные нельзя, можно попробовать сначала выбрать все ссылки документов за период во временную таблицу (по индексированному полю Дата), а затем наложить фильтр по грузополучателю. Однако, как показала практика обсуждения, на небольших объемах (50к записей) этот метод может быть даже медленнее из-за накладных расходов на создание временной таблицы.

Резюме

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

← На главную