В процессе разработки и отладки конфигураций в файловом режиме многие разработчики сталкиваются с ситуацией, когда один и тот же запрос в клиент-серверной рабочей базе отрабатывает за доли секунды, а в локальной файловой базе приводит к зависанию интерфейса на минуты. Особенно ярко это проявляется в динамических списках документов и справочников при наличии соединений с другими таблицами.
Разберем детально, почему файловая СУБД платформы 1С:Предприятие ведет себя иначе, чем оптимизатор промышленных серверов баз данных, какие ошибки в запросах к этому приводят и как оптимизировать работу списков.
Рассмотрим реальный пример запроса динамического списка, вызывающего существенную задержку в файловой базе:
ВЫБРАТЬ ПЕРВЫЕ 50
ДокЗаявкаКлиента.Дата,
ДокЗаявкаКлиента.Номер,
ДокЗаявкаКлиента.Клиент,
ДокЗаявкаКлиента.Вес,
ДокЗаявкаКлиента.Объем,
ДокЗаявкаКлиента.Стоимость,
ДокЗаявкаКлиента.СпособПогрузки,
ДокЗаявкаКлиента.ДатаПогрузкиДляОтбора КАК ДатаПогрузки,
ДокЗаявкаКлиента.ДатаРазгрузкиДляОтбора КАК ДатаРазгрузки,
ДокЗаявкаКлиента.ТребованиеКТС,
ДокЗаявкаКлиента.НазваниеГруза,
ДокЗаявкаКлиента.ПредоставитьДо,
ДокЗаявкаКлиента.ПунктОтправленияПредставление КАК ПунктОтправления,
ДокЗаявкаКлиента.ПунктНазначенияПредставление КАК ПунктНазначения,
ДокЗаявкаКлиента.Автор,
ДокЗаявкаКлиента.Клиент.ОсновнойМенеджерПокупателя КАК ОтветственныйМенеджер,
ДокЗаявкаКлиента.ВторойЛогист,
ДокЗаявкаКлиента.Ссылка,
ДокЗаявкаКлиента.Комментарий,
ДокЗаявкаКлиента.СтоимостьДляПеревозчика,
ДокЗаявкаКлиента.ТипТС,
ЕСТЬNULL(уатЗаказГрузоотправителя.Ссылка, ЗНАЧЕНИЕ(Документ.уатЗаказГрузоотправителя.ПустаяСсылка)) КАК Заказ,
ЕСТЬNULL(СтатусЗаявкиКлиентаСрезПоследних.Статус, ЗНАЧЕНИЕ(Перечисление.СтатусыПредварительнойЗаявки.ПустаяСсылка)) КАК Статус,
уатЗаказГрузоотправителя.Ответственный КАК ОтветственныйЛогист
ИЗ
Документ.ЗаявкаКлиента КАК ДокЗаявкаКлиента
ЛЕВОЕ СОЕДИНЕНИЕ Документ.уатЗаказГрузоотправителя КАК уатЗаказГрузоотправителя
ПО (ДокЗаявкаКлиента.Ссылка = (ВЫРАЗИТЬ(уатЗаказГрузоотправителя.ДокументОснование КАК Документ.ЗаявкаКлиента)))
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СтатусЗаявкиКлиента.СрезПоследних КАК СтатусЗаявкиКлиентаСрезПоследних
ПО (СтатусЗаявкиКлиентаСрезПоследних.ЗаявкаКлиента = ДокЗаявкаКлиента.Ссылка)
В клиент-серверном режиме (например, под управлением Microsoft SQL Server или PostgreSQL) оптимизатор СУБД строит сложный план выполнения, использует хэш-соединения (Hash Match), адаптивные соединения и кэширование промежуточных данных. Встроенный движок файловой базы 1С (файл 1Cv8.1CD) использует упрощенные алгоритмы соединения и последовательного перебора, из-за чего неоптимальные конструкции приводят к резкому падению скорости.
Проанализируем конкретные узкие места в представленном запросе и архитектуре файлового движка:
ВЫРАЗИТЬ(уатЗаказГрузоотправителя.ДокументОснование КАК Документ.ЗаявкаКлиента) в условии ПО делает предикат неоптимизируемым. Файловый движок не может использовать индекс по реквизиту ДокументОснование составного типа, так как к полю применяется функция преобразования типов. В результате платформа выполняет полное сканирование таблицы заказов на каждую строку заявок.СрезПоследних при отсутствии рассчитанных итогов разворачивается платформой во вложенный подзапрос с группировкой по максимальной дате. В файловом режиме соединение физической таблицы с неиндексированным подзапросом приводит к катастрофическому замедлению.ДокЗаявкаКлиента.Клиент.ОсновнойМенеджерПокупателя формирует дополнительное неявное левое соединение со справочником клиентов, что увеличивает объем оперативной обработки при каждом обновлении списка.уатЗаказГрузоотправителя по документу-основанию потенциально порождает связь «один-ко-многим». Если по одной заявке введено несколько заказов, строки списка задваиваются, что нарушает целостность ключей динамического списка и перегружает механизм позиционирования платформы.Выясним, как ускорить работу с виртуальной таблицей среза. Для периодических регистров сведений платформа 1С предоставляет механизм хранения актуальных срезов. Если в свойствах регистра сведений включен режим «Итоги и агрегаты» (хранение итогов), платформа физически поддерживает актуальную таблицу последних записей. В этом случае обращение к таблице СрезПоследних выполняется напрямую к физической таблице итогов с использованием штатных индексов, без динамического вычисления максимальных дат через подзапросы.
Для устранения полного сканирования таблицы привяжем документы через явный ссылочный тип. Если реквизит ДокументОснование имеет составной тип данных, рекомендуется:
ДокументСсылка.ЗаявкаКлиента с установленным свойством «Индексировать» и соединять таблицы напрямую по равенству ссылок:
ЛЕВОЕ СОЕДИНЕНИЕ Документ.уатЗаказГрузоотправителя КАК уатЗаказГрузоотправителя
ПО (уатЗаказГрузоотправителя.ЗаявкаКлиента = ДокЗаявкаКлиента.Ссылка)
Разберем параметры динамического списка, которые напрямую влияют на объем считываемых данных:
Документ.ЗаявкаКлиента). Если свойство не заполнено, платформа не может применять оптимизированное постраничное динамическое считывание порциями по 20–40 строк и считывает весь объем данных целиком.При частой реструктуризации и доработке конфигурации файл базы данных .1CD подвержен внутренней фрагментации. Для восстановления быстродействия файлового хранилища выполним следующие шаги:
%LOCALAPPDATA%\1C\1cv8 и %APPDATA%\1C\1cv8.