Не думать о секундах свысока…

Несколько примеров оптимизации типовой конфигурации УТ11. Описанные приемы подходят для многих других конфигураций.

 

 

 1. Справочники.УпаковкиЕдиницыИзмерения.ТекстЗапросаКоэффициентаУпаковки()

Обратите на текст запроса, который возвращает эта функция. В типовой УТ он используется порядка 500 раз. Его добавляют в отчеты, модули документов и так далее. Думаю, Вы уже догадались, если организация торгует штучным товаром и не объединяет товар в упаковки, то этот запрос просто возвращает число 1. Функциональная опция «ИспользоватьУпаковкиНоменклатуры», на подстановку не влияет.

Например, при формировании запроса по подбору заменил строки кода

ШаблонТекстаЗапроса = СтрЗаменить(ШаблонТекстаЗапроса,"&ТекстЗапросаКоэффициентУпаковки1",
Справочники.УпаковкиЕдиницыИзмерения.ТекстЗапросаКоэффициентаУпаковки("ЦеныНоменклатуры.Упаковка","ЦеныНоменклатуры.Номенклатура"));

На код

ШаблонТекстаЗапроса = СтрЗаменить(ШаблонТекстаЗапроса,"&ТекстЗапросаКоэффициентУпаковки1",1);

и подбор товаров стал работать в два раза быстрее.

Если Вам будет интересно, я напишу обработку для проверки – можно ли в Вашей базе заменить текст запроса на 1.

 

 2. Работа над ошибками

Понятно, что регистрация и обработка ошибки занимает определенное время поэтому необходимо ежедневно просматривать журнал регистрации и технологический журнал, непримиримо устранять источники ошибок. Воспользуемся результатами статьи //infostart.ru/public/825405/ пункт «Наиболее частые ошибки»

При анализе технологического журнала было выявлено много событий EXCP (Например, до 11 тысяч в час). Сравнил с журналом регистрации, выяснил — это фоновые задания, которые запускаются, например при «Быстром поиске» в списке заказов, в списке номенклатуры а затем прерываются: пользователь не дождался. В журнале регистрации фоновое задание отменено или прервано.

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

Кстати, некоторые RLS ограничения тоже выглядят лишними. В технологическом журнале их можно искать по слову "DUMMY".

 

 3. Динамические списки

Нужно отключать типовой поиск, который запускает фоновые задание. Кроме этого, обязательно нужно ограничивать период (для списка документов). Журнал документов за месяц открывается в двенадцать раз быстрее, чем за год. Динамическое считывание отключил: лучше один большой запрос, чем много маленьких. Все изменения нужно делать не в форме, а в коде. В общем, предлагаю такой вид процедуры в форме списка:

Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

Элементы.Список.ПоискПриВводе = ПоискВТаблицеПриВводе.Авто;
Элементы.Список.ПоложениеСтрокиПоиска = ПоложениеСтрокиПоиска.Нет;
Элементы.Список.Период.ДатаНачала = ДобавитьМесяц( ТекущаяДата(), -1 );
Элементы.Список.Период.ДатаОкончания = ДобавитьМесяц( ТекущаяДата(), 1 );
Список.ДинамическоеСчитываниеДанных = Ложь;

...
КонецПроцедуры

Для списка справочника номенклатуры потребовалось изменить модуль менеджера:

Процедура ОбработкаПолученияДанныхВыбора(ДанныеВыбора, Параметры, СтандартнаяОбработка)

Если Параметры.Свойство("СтрокаПоиска")
И ТипЗНЧ("Параметры.СтрокаПоиска") = Тип("Строка")
И СтрДлина(Параметры.СтрокаПоиска) = 1 Тогда

СтандартнаяОбработка = Ложь;
Возврат;
КонецЕсли;

...
КонецПроцедуры

При вводе одной буквы в списке теперь не запускается фоновое задание, а появляется окошко поиска. Добавление кода лучше видно при обновлении, чем изменение визуальной формы. Если работаете с расширениями конфигурации – используйте расширение. Не забудьте указать правильное имя элемента формы-списка и протестировать.

 

 4. Давно мечтал о инструменте, который бы находил в конфигурации все объектные чтения

И наконец моя мечта сбылась !! Как известно, при объектном чтении элемента справочника программа 1С считывает и кеширует все реквизиты. Запрос в формате SDBL имеет вид: «SELECT ID, Version, Marked, PredefinedID…». Объектные чтения, которые происходят в форме элемента в событии ПриЧтенииНаСервере() неизбежны, но имеют другой формат запроса. Воспользуемся результатами статьи //infostart.ru/public/825405/ — с помощью GIT BASH суммируем все контексты по таким запросам.

Как он работает пошагово – рассказывал в упомянутой статье, повторяться не буду. Специалисты, которые профессионально занимаются анализом технологического журнала, используют свои привычные скрипты. Они тоже смогут воспользоваться этими результатами: достаточно добавить фильтр по тексту запроса. Простая идея, но подобных примеров поиска не встречал. В своей базе нашел несколько случаев объектного чтения и с удовольствием их устранил.

 

 5. Поиск запросов, поля которых имеют тип «ХранилищеЗначений».

Как Вы понимаете, такие запросы работают без ошибок на уровне СУБД и на уровне 1С, но если полученные поля типа хранилище значений не используются, то трафик СУБД-1С можно уменьшить.

Сначала в программе 1С выберем SDBL-имена для полей типа хранилище значений. У меня получился примерно такой код для внешней обработки:

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

ПоляТипаХранилище = "";
СтруктураБазы = ПолучитьСтруктуруХраненияБазыДанных();
Для каждого СтрокаСтруктурыБазы Из СтруктураБазы Цикл
Для каждого СтрокаСтруктурыПолей Из СтрокаСтруктурыБазы.Поля Цикл
СтрокаТЧ = Объект.ТабличнаяЧасть1.Добавить();
СтрокаТЧ.ИмяТаблицыХранения = СтрокаСтруктурыБазы.ИмяТаблицыХранения;
ЗаполнитьЗначенияСвойств(СтрокаТЧ, СтрокаСтруктурыПолей);
Если СтрНайти(СтрокаСтруктурыБазы.Метаданные, "Справочник.") > 0
И СтрНайти(СтрокаСтруктурыБазы.Метаданные, "ТабличнаяЧасть") = 0
И СтрокаСтруктурыПолей.ИмяПоля <> "" Тогда

ИмяСправочника = СтрЗаменить(СтрокаСтруктурыБазы.Метаданные, "Справочник.", "");
МетаСправочник = Метаданные.Справочники[ИмяСправочника];
Реквизит= МетаСправочник.Реквизиты.Найти(СтрокаСтруктуры.ИмяПоля);
Если Реквизит <> Неопределено
И Реквизит.Тип.СодержитТип( Тип("ХранилищеЗначения") ) Тогда

ПоляТипаХранилище = ПоляТипаХранилище + ?(ПоляТипаХранилище="","","|") + СтрокаСтруктуры.ИмяПоляХранения;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЦикла;
Объект.ПоляХранилищ = "cat *.* | egrep '.(" + ПоляТипаХранилище + ")' --color -A3 -B3";

КонецПроцедуры

Итоговая строка имеет вид cat *.* | egrep ‘.( ПоляТипаХранилище)’ —color -A3 -B3 Копируем в командную строку GIT BASH и запускаем.

 

 6. ПодборТоваровСервер.ЕстьЗначенияЦенПозжеДатыПодбора()

В этой функции запрос к таблице периодического регистра будет быстрее запроса к срезу последних.

ВЫБРАТЬ РАЗРЕШЕННЫЕ
МАКСИМУМ(Цены.Период) КАК Период
ИЗ
РегистрСведений.ЦеныНоменклатуры КАК Цены
ГДЕ
Цены.ВидЦены В(&ВидыЦен)

В регистре ЦеныНоменклатуры включено использование Среза последних. Поэтому запросы используют разные таблицы данных в качестве источника. Для измерения «ВидЦены» включен признак «Ведущее», поэтому индексирование недоступно, индекс в регистре существует, НО индекс в таблице среза НЕ существует, о чем честно написано в документации https://its.1c.ru/db/metod8dev/content/1590/hdoc. Поэтому любые отборы по второму (третьему) измерению без условий на предыдущие измерения в таблице среза цен вызывают сканирование таблицы. Это нужно иметь ввиду.

 

 

 7. Открытое письмо 1С:Эксперту и хорошему человеку Виктору Богачеву

 

 

P.S. На логотипе статьи часы с подводной лодки. Символизируют секунды. Мой коллега плавал.

21 Comments

  1. rom-x

    При раскрытии 2-5 пунктов пусто

    Reply
  2. vasilev2015

    Здравствуйте !

    Использовал спойлеры как заголовки потому что они заметные.

    За спойлеры 1 и 6 спрятал код из типовой конфигурации, чтобы он не занимал место.

    Остальные спойлеры не знаю, чем занять.

    Reply
  3. e][tend

    (0) По тексту статьи, сразу было понятно чья школа. 7 пункт подтвердил догадки!

    Сейчас сам прохожу обучение у Виктора)

    Reply
  4. kuzyara
    5. Поиск запросов, поля которых имеют тип «ХранилищеЗначений».

    но полученные поля типа хранилище значений Вы не сможете использовать из выборки запроса. Значит, трафик СУБД-1С можно уменьшить.

    Почему это не сможем?

     Запрос = Новый Запрос;
    Запрос.Текст =
    «ВЫБРАТЬ ПЕРВЫЕ 10
    | ФайлыСНеизвестнымиПараметрами.ИмяФайла КАК ИмяФайла,
    | ФайлыСНеизвестнымиПараметрами.ФайлДанных КАК ФайлДанных,
    | ФайлыСНеизвестнымиПараметрами.ДатаЗагрузкиФайла КАК ДатаЗагрузкиФайла
    |ИЗ
    | РегистрСведений.ФайлыСНеизвестнымиПараметрами КАК ФайлыСНеизвестнымиПараметрами»;
    Выборка = Запрос.Выполнить().Выбрать();
    
    Пока Выборка.Следующий() Цикл
    // получение в запросе реквизита типа ХранилищеЗначений
    // приводит к свопу во временный каталог сразу по всем записям
    ДвДанные = Выборка.ФайлДанных.Получить(); 

    Показать

    Вызов метода Выборка.ФайлДанных.Получить() не вызывает обращения к БД.

    Reply
  5. vasilev2015

    (4) Здравствуйте !

    Изменил формулировку на компромиссную. Спасибо за внимательность.

    Reply
  6. SlavaKron

    (4) Зачем бы такой тип нужен был тогда. Может это актуально для запросов динамических списков, но я что-то сомневаюсь, что список будет тянуть ХЗ с сервера.

    Reply
  7. vasilev2015

    (6) Здравствуйте !

    Это в контексте поиска ошибок.

    Ведь кто-то пишет запросы типа » Выбрать * ИЗ * » и не только в динамических списках.

    Reply
  8. Rustig

    (0) отличная статья!

    Reply
  9. vasilev2015

    (8) Здравствуйте !

    Надеюсь, кому-то пригодится.

    Reply
  10. kuzyara

    (5)

    Изменил формулировку на компромиссную. Спасибо за внимательность.

    С таким подходом на эксперта сложно будет сдать.

    Reply
  11. vasilev2015

    (10)

    Компромисс — это искусство разделить пирог так, чтобы каждый был уверен, что лучший кусок достался ему.

    Reply
  12. AlexeyT1978

    уже внедрил п.1 себе в конфу, хороший мануал

    Reply
  13. vasilev2015

    (12) Здравствуйте !

    У вас сколько пользователей ?

    Долго подбор открывался ?

    Reply
  14. AlexeyT1978

    (13) 100

    Reply
  15. vasilev2015

    (14) Краткость — сестра ))

    Reply
  16. morin

    Думаю, никто не будет против, если я немного дополню список:

    — отключаем заполнение объектов по статистике (такое заполнение нужно очень не многим, но сильно затормаживает систему), необходимо поставить заглушку в ЗаполнениеСвойствПоСтатистикеПереопределяемый.ПриОпределенииЗначенияРеквизитаПоСтатистике(): СтандартнаяОбработка = Ложь;

    — присмотритесь к функции ПродажиСервер.ПолучитьОтветственногоПоСкладу(), вызывается при инициализации реализации и заполняет необязательный реквизит Отпустил и ОтпустилДолжность примерными значениями, тоже польза не соответствует издержкам.

    Reply
  17. acanta

    Почему заполнение по статистике реализовано через запрос, а не при помощи записи в регистр сведений фоновым заданием?

    Reply
  18. vasilev2015

    (17) Здравствуйте, Анна !

    что значит «заполнение по статистике» ?

    Reply
  19. acanta

    Я имею ввиду не статистику СУБД, а тормоза при вводе нового документа из за обращения к базе.

    Reply
  20. morin

    (19) Он не в курсе.

    Reply
  21. vasilev2015

    (20) ага, догадался. От модуля «ЗаполнениеСвойствПоСтатистикеПереопределяемый» я еще не успел пострадать. Возьму на заметку.

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *