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

Публикация № 1058730

Администрирование - Оптимизация БД (HighLoad)

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

 

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

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

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

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

На код

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

 

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

 

 

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

54

См. также

Специальные предложения

Комментарии
Избранное Подписка Сортировка: Древо
1. rom-x 152 22.05.19 09:52 Сейчас в теме
При раскрытии 2-5 пунктов пусто
2. vasilev2015 1377 22.05.19 10:02 Сейчас в теме
Здравствуйте !

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

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

Остальные спойлеры не знаю, чем занять.
3. e][tend 22.05.19 10:53 Сейчас в теме
(0) По тексту статьи, сразу было понятно чья школа. 7 пункт подтвердил догадки!
Сейчас сам прохожу обучение у Виктора)
4. kuzyara 785 22.05.19 11:22 Сейчас в теме
5. Поиск запросов, поля которых имеют тип «ХранилищеЗначений».
но полученные поля типа хранилище значений Вы не сможете использовать из выборки запроса. Значит, трафик СУБД-1С можно уменьшить.

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

Вызов метода Выборка.ФайлДанных.Получить() не вызывает обращения к БД.
SlavaKron; +1 Ответить
5. vasilev2015 1377 22.05.19 11:37 Сейчас в теме
(4) Здравствуйте !

Изменил формулировку на компромиссную. Спасибо за внимательность.
10. kuzyara 785 24.05.19 04:23 Сейчас в теме
(5)
Изменил формулировку на компромиссную. Спасибо за внимательность.

С таким подходом на эксперта сложно будет сдать.
11. vasilev2015 1377 24.05.19 08:35 Сейчас в теме
(10)

Компромисс — это искусство разделить пирог так, чтобы каждый был уверен, что лучший кусок достался ему.
6. SlavaKron 22.05.19 11:40 Сейчас в теме
(4) Зачем бы такой тип нужен был тогда. Может это актуально для запросов динамических списков, но я что-то сомневаюсь, что список будет тянуть ХЗ с сервера.
7. vasilev2015 1377 22.05.19 11:50 Сейчас в теме
(6) Здравствуйте !

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

Ведь кто-то пишет запросы типа " Выбрать * ИЗ * " и не только в динамических списках.
8. Rustig 1186 23.05.19 09:38 Сейчас в теме
9. vasilev2015 1377 23.05.19 14:35 Сейчас в теме
(8) Здравствуйте !

Надеюсь, кому-то пригодится.
12. AlexeyT1978 78 29.05.19 17:41 Сейчас в теме
уже внедрил п.1 себе в конфу, хороший мануал
13. vasilev2015 1377 29.05.19 19:23 Сейчас в теме
(12) Здравствуйте !

У вас сколько пользователей ?
Долго подбор открывался ?
14. AlexeyT1978 78 04.06.19 16:20 Сейчас в теме
15. vasilev2015 1377 04.06.19 16:33 Сейчас в теме
16. morin 13 15.06.19 21:40 Сейчас в теме
Думаю, никто не будет против, если я немного дополню список:
- отключаем заполнение объектов по статистике (такое заполнение нужно очень не многим, но сильно затормаживает систему), необходимо поставить заглушку в ЗаполнениеСвойствПоСтатистикеПереопределяемый.ПриОпределенииЗначенияРеквизитаПоСтатистике(): СтандартнаяОбработка = Ложь;
- присмотритесь к функции ПродажиСервер.ПолучитьОтветственногоПоСкладу(), вызывается при инициализации реализации и заполняет необязательный реквизит Отпустил и ОтпустилДолжность примерными значениями, тоже польза не соответствует издержкам.
17. acanta 63 15.06.19 21:45 Сейчас в теме
Почему заполнение по статистике реализовано через запрос, а не при помощи записи в регистр сведений фоновым заданием?
18. vasilev2015 1377 18.06.19 08:59 Сейчас в теме
(17) Здравствуйте, Анна !

что значит "заполнение по статистике" ?
19. acanta 63 18.06.19 09:16 Сейчас в теме
Я имею ввиду не статистику СУБД, а тормоза при вводе нового документа из за обращения к базе.
20. morin 13 20.06.19 08:30 Сейчас в теме
(19) Он не в курсе.
vasilev2015; acanta; +2 Ответить
21. vasilev2015 1377 20.06.19 14:51 Сейчас в теме
(20) ага, догадался. От модуля "ЗаполнениеСвойствПоСтатистикеПереопределяемый" я еще не успел пострадать. Возьму на заметку.
Оставьте свое сообщение