Работа в классической конфигурации 1С:Предприятие 7.7, особенно в связке с SQL-сервером, при больших объемах данных часто преподносит сюрпризы в виде внезапных «тормозов». Одной из самых распространенных проблем является замедление при записи или редактировании элементов справочника Номенклатура. Рассмотрим детально, почему это происходит, как диагностировать проблему и какие шаги предпринять для оптимизации системы.
Первым делом нам необходимо выяснить, на каком именно этапе происходит задержка. Если система «подвисает» в момент нажатия кнопки «ОК» или при записи элемента, нам поможет штатный инструмент — Замер производительности. В конфигураторе или режиме отладки запустим процесс и выполним запись элемента. Проанализируем типичный замер производительности, который часто встречается в подобных ситуациях:
Глобальный модуль | 1018 | Пока ЦеныТовара.ПолучитьЭлемент() = 1 Цикл | 501981 | 85.191610 | 51.78
Справочник.Номенклатура.Форма | 1328 | глЗаписьПериодическихРеквизитов(Контекст); | 1 | 76.893254 | 46.74
Обратим внимание на первую строку. Мы видим более 500 000 итераций в цикле. Это критический показатель. Выясним причину: почему при записи одного товара система перебирает полмиллиона записей? Как правило, это связано с обновлением формы списка, которое инициируется сразу после закрытия или записи карточки товара. Если в форме списка выведены колонки с ценами или остатками, система начинает пересчитывать их для всех видимых строк.
Одной из наиболее коварных ловушек в 1С 7.7 является поведение метода ИспользоватьВладельца(). Рассмотрим стандартную функцию получения цены, которая часто модифицируется программистами:
Функция глВернутьЦену(Товар, КатегорияЦены) Экспорт
Перем ЦеныТовара;
ЦеныТовара = СоздатьОбъект("Справочник.Цены");
ЦеныТовара.ИспользоватьВладельца(Товар);
ЦеныТовара.ВыбратьЭлементы();
Пока ЦеныТовара.ПолучитьЭлемент() = 1 Цикл
Если ЦеныТовара.ПометкаУдаления() = 1 Тогда
Продолжить;
КонецЕсли;
Если ЦеныТовара.КатегорияЦены = КатегорияЦены Тогда
Возврат ЦеныТовара.ТекущийЭлемент();
КонецЕсли;
КонецЦикла;
КонецФункции
Проанализируем ситуацию: если переменная Товар окажется пустой (например, при создании нового элемента, который еще не записан в базу, или из-за ошибки передачи контекста в форму списка), метод ИспользоватьВладельца(Товар) фактически сбрасывает фильтр. В результате ВыбратьЭлементы() начинает перебирать весь справочник цен целиком по всей базе данных. Если у вас 500 000 записей о ценах, система будет честно просматривать каждую для каждой строки списка номенклатуры.
Решение: Всегда добавляйте проверку на пустое значение или наличие ссылки перед началом выборки:
Если (ПустоеЗначение(Товар) = 1) ИЛИ (Товар.Выбран() = 0) Тогда
Возврат "";
КонецЕсли;
Даже при корректном владельце метод ВыбратьЭлементы() в цикле — это не самое быстрое решение для SQL-базы. Рассмотрим варианты ускорения этого процесса:
ВыбратьЭлементыПоРеквизиту: Если у вас в справочнике Цены включена сортировка (индекс) по реквизиту КатегорияЦены, можно использовать этот метод. Однако стоит помнить, что в 7.7 метод ИспользоватьВладельца() и ВыбратьЭлементыПоРеквизиту() не всегда эффективно работают вместе на уровне SQL-запроса.Запрос вместо объектного перебора справочника позволяет SQL-серверу более эффективно использовать свои индексы.В замере производительности мы видели выполнение процедуры глЗаписьПериодическихРеквизитов. В системе 1С 7.7 периодические реквизиты хранятся в огромной общей таблице 1SCONST. При записи элемента номенклатуры система обращается к этой таблице для записи новых значений цен или налогов.
Проанализируем причины замедления в этой части:
1SCONST постоянно растет и обновляется, что ведет к сильной фрагментации. Необходимо регулярно выполнять перестроение индексов (Reindex) средствами SQL Server.Если ваша база является частью распределенной сети, каждая запись объекта регистрируется в специальной таблице изменений — 1SUPDTS. Выясним, как это влияет на скорость. Если обмен с какой-то из периферийных точек давно не выполнялся, таблица регистраций начинает бесконтрольно расти. При каждой записи номенклатуры SQL-сервер вынужден тратить время на обслуживание этой таблицы.
Рекомендация: Убедитесь, что все обмены проходят успешно. Если в таблице 1SUPDTS скопились миллионы записей, которые уже не актуальны, рассмотрите возможность их принудительной очистки (после консультации со специалистом и создания резервной копии).
Иногда проблема кроется не в коде, а в состоянии самой СУБД. Проанализируем план обслуживания базы:
UPDATE STATISTICS для ключевых таблиц (справочники, 1SCONST, 1SUPDTS).DBCC FREEPROCCACHE может помочь сбросить текущие планы и заставить сервер построить их заново.Разберем по шагам последовательность действий для программиста:
глВернутьЦену и аналогичные) жесткую проверку на Выбран() = 1 для переданного объекта.1SUPDTS. Если она переполнена — завершите все обмены или проведите профилактику УРБД.Применяя эти методы в комплексе, мы сможем добиться мгновенной записи элементов даже в очень крупных базах данных 1С 7.7, обеспечивая комфортную работу пользователей.