При разработке и оптимизации высоконагруженных конфигураций 1С особое внимание уделяется работе с регистрами накопления. Неправильное проектирование структуры регистра или некорректно составленные условия в параметрах виртуальных таблиц могут приводить к деградации производительности всей системы, длительным блокировкам и избыточной нагрузке на дисковую подсистему СУБД. Разберем практический пример работы с остатками и проанализируем поведение СУБД на низком уровне.
Рассмотрим регистр накопления остатков ТоварыНаСкладах со следующей последовательностью реквизитов:
Склад, Номенклатура, ХарактеристикаНоменклатуры, СерияНоменклатуры, Качество.Количество, КоличествоЛ.Проанализируем три типичных запроса на получение остатков номенклатуры:
Запрос 1 (Отбор только по номенклатуре):
ВЫБРАТЬ
Товары.Номенклатура,
Товары.КоличествоОстаток
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(, , , Номенклатура = &Номенклатура) КАК Товары
Запрос 2 (Отбор по номенклатуре и складу):
ВЫБРАТЬ
Товары.Номенклатура,
Товары.КоличествоОстаток
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(, , , Номенклатура = &Номенклатура И Склад = &Склад) КАК Товары
Запрос 3 (Отбор по номенклатуре и качеству):
ВЫБРАТЬ
Товары.Номенклатура,
Товары.КоличествоОстаток
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(, , , Номенклатура = &Номенклатура И Качество = &Качество) КАК Товары
Выясним причину, почему данные запросы будут кардинально отличаться по времени выполнения в реальной информационной базе:
Склад и Номенклатура). СУБД выполняет операцию поиска по индексу (Index Seek), мгновенно позиционируясь на нужной ветке данных.Склад). СУБД не может выполнить точечный поиск по кластерному индексу и выполняет полное или частичное сканирование индекса (Index Scan), считывая значительно больше страниц с диска и из оперативной памяти.Склад, а также измерения ХарактеристикаНоменклатуры и СерияНоменклатуры. Запрос приводит к сканированию индекса с последующей фильтрацией по предикату качества, что создает максимальную нагрузку.Чтобы понять внутреннюю механику, рассмотрим физическую структуру регистра в СУБД. Регистр накопления остатков состоит из двух таблиц: таблицы движений и таблицы итогов. При запросе к виртуальной таблице Остатки без указания периода платформа считывает данные из таблицы итогов по наиболее актуальному рассчитанному срезу.
Кластерный индекс таблицы итогов формируется строго в порядке следования измерений в дереве конфигурации: Период + Измерение1 + Измерение2 + ... + ИзмерениеN. В нашем случае структура индекса выглядит так: Период + Склад + Номенклатура + ХарактеристикаНоменклатуры + СерияНоменклатуры + Качество.
По правилам работы составных B-Tree индексов в реляционных базах данных эффективный поиск по индексу возможен только слева направо без пропусков. Если в условии отбора отсутствует левый префикс (в нашем случае Склад), использование индекса для прямого перехода к данным становится невозможным.
Распространенное заблуждение — включить свойство «Индексировать» у измерения Номенклатура в надежде ускорить работу виртуальной таблицы остатков. Разберем, почему это не поможет:
Установка признака индексации у отдельного измерения создает дополнительный некластерный индекс исключительно в таблице движений регистра. На физическую структуру основного кластерного индекса в таблице итогов этот флаг никакого влияния не оказывает. Соответственно, чтение из виртуальной таблицы остатков по-прежнему будет неоптимальным.
Для оптимизации работы с регистром применим следующие инженерные подходы:
Номенклатура на первое место в списке измерений регистра. Номенклатура обладает высокой селективностью (большое количество уникальных значений), что обеспечит мгновенную локализацию данных при поиске по индексу.Склад).Проанализируем сопутствующие риски неоптимальных запросов при параллельной работе пользователей:
Для обеспечения стабильной скорости выполнения запросов к итогам регистров накопления администратор базы данных и программист должны контролировать выполнение следующих обязательных регламентов:
УправлениеИтогамиИАгрегатами. Граница итогов должна быть установлена на текущий или будущий месяц. Если граница отстает от текущей даты, любой запрос остатков будет считывать устаревший срез и динамически досчитывать остаток по таблице движений, что снижает скорость работы на порядки.