|
Обращение к реквизиту справочника через точку | ☑ | ||
---|---|---|---|---|
0
ejikbeznojek
05.03.18
✎
15:42
|
Всем привет.
Есть нетиповая конфа на 8.1 Есть документ с табличной частью. Перед записью документа есть цикл по этой ТЧ, в которой происходит ряд проверок. [code] Для Каждого СтрокаТЧ Из ДокОбъект.Товары Цикл СтрокаДубля=СтрокиДублей.Получить(СтрокаТЧ.Номенклатура); Если СтрокаТЧ.Номенклатура.ВидНоменклатуры<>Перечисления.ВидыНоменклаутры.ПодарочныйСертификат Тогда Замер производительности показывает, что это условие выполняется около 30% времени от всей операции по записи и проведению документа. ВидНоменклатуры это не составной реквизит с типом значения - перечисление. Индексировать не стоит, но я пробовал поставить это ничего не дало. Если переделать на запрос, тогда будет 7% процентов вместо 30, но я как-то ожидаю увидеть меньше 0,1%. В чём может быть дело? [/code] |
|||
1
hhhh
05.03.18
✎
15:48
|
(0) запрос в студию
|
|||
2
ejikbeznojek
05.03.18
✎
15:51
|
https://prnt.sc/in3bi9
Пробовал переделывать с Если СтрокаТЧ.Номенклатура.ВидНоменклатуры<>Перечисления.ВидыНоменклаутры.ПодарочныйСертификат Тогда на запрос.текст="ВЫБРАТЬ | Номенклатура.ВидНоменклатуры как ВидНоменклатуры |ИЗ | Справочник.Номенклатура КАК Номенклатура |ГДЕ | Номенклатура.Ссылка = &Ссылка"; если запрос.выполнить.выгрузить().получить(0).ВидНоменклатуры<>Перечисления.ВидыНоменклаутры.ПодарочныйСертификат Тогда |
|||
3
ИС-2
naïve
05.03.18
✎
15:53
|
текст вопроса как у меня - почти 1 в один:
Оптимизация обращений к реквизитам объектов через точку Оптимизация обращений к реквизитам объектов через точку написал функцию Функция ЗначРекв(Источник, ПутьКРеквизитамПовтИсп,ПутьКРеквизитамЖивым = "",ОбновитьПовтИсп = Ложь,ДопПараметры = Неопределено) Экспорт ЧерезПовтИсп = Ложь; ТипИсточника = ТипЗнч(Источник); // объекты нельзя передавать в модуль повторного использования Если Документы.ТипВсеСсылки().СодержитТип(ТипИсточника) Тогда ЧерезПовтИсп = Истина; ИначеЕсли Перечисления.ТипВсеСсылки().СодержитТип(ТипИсточника) Тогда ЧерезПовтИсп = Истина; ИначеЕсли Справочники.ТипВсеСсылки().СодержитТип(ТипИсточника) Тогда ЧерезПовтИсп = Истина; КонецЕсли; // надо получить все актуальные данные Если ПутьКРеквизитамПовтИсп = "" Тогда ЧерезПовтИсп = Ложь; КонецЕсли; Если ЧерезПовтИсп Тогда СтрокаВызоваПовтИсп = ""; СтрокаВызоваЖивогоВызова = ""; ИмяЖивогоРеквизита = ""; МассивРеквзитов = _ПовтИсп.РазложитьСтрокуВМассивПодстрок(ПутьКРеквизитамПовтИсп,"."); МассивРеквзитовЖивых = _ПовтИсп.РазложитьСтрокуВМассивПодстрок(ПутьКРеквизитамЖивым,"."); // все, что после 1-го живого реквизита получаем из актуальных данных Если МассивРеквзитовЖивых.Количество() > 0 Тогда ИмяЖивогоРеквизита = МассивРеквзитовЖивых[0]; КонецЕсли; // признак, что все последубщие данные надо брать из актуальных данных ВЖивойВызов = Ложь; Для Каждого ТекРеквизит из МассивРеквзитов Цикл Если ТекРеквизит = ИмяЖивогоРеквизита Тогда ВЖивойВызов = Истина; СтрокаВызоваЖивогоВызова = СтрокаВызоваЖивогоВызова + ?(СтрокаВызоваЖивогоВызова = "","",".") + ТекРеквизит; ИначеЕсли не ВЖивойВызов Тогда СтрокаВызоваПовтИсп = СтрокаВызоваПовтИсп + ?(СтрокаВызоваПовтИсп = "","",".") + ТекРеквизит; иначе СтрокаВызоваЖивогоВызова = СтрокаВызоваЖивогоВызова + ?(СтрокаВызоваЖивогоВызова = "","",".") + ТекРеквизит;; КонецЕсли; КонецЦикла; если не СтрокаВызоваПовтИсп = "" Тогда Рез = _ПовтИсп.ЗначРекв(Источник, СтрокаВызоваПовтИсп,ДопПараметры); КонецЕсли; если не ПутьКРеквизитамЖивым = "" // передан реквзит после которого не надо вычислять и не ВЖивойВызов Тогда СтрокаВызоваЖивогоВызова = СтрокаВызоваЖивогоВызова + ?(СтрокаВызоваЖивогоВызова = "","",".") + ПутьКРеквизитамЖивым; КонецЕсли; Если не СтрокаВызоваЖивогоВызова = "" // это составной тип и не Рез = Неопределено Тогда Рез = Вычислить("Рез"+"." + СтрокаВызоваЖивогоВызова); КонецЕсли; иначе СтрокаВызоваЖивогоВызова = ПутьКРеквизитамПовтИсп; Если не ПутьКРеквизитамЖивым = "" Тогда СтрокаВызоваЖивогоВызова = ?(СтрокаВызоваЖивогоВызова = "","",".") + ПутьКРеквизитамЖивым; КонецЕсли; Рез = Вычислить("Источник" + "." + СтрокаВызоваЖивогоВызова); КонецЕсли; Возврат Рез; КонецФункции в модуле _ПовтИсп: Функция ЗначРекв(Источник, ПутьКРеквизитам,ДопПараметры) Экспорт Реквзиты = РазложитьСтрокуВМассивПодстрок(ПутьКРеквизитам,"."); Если Реквзиты.количество() = 0 Тогда Рез = Источник; иначе Рез = Вычислить("Источник" + "." +ПутьКРеквизитам); КонецЕсли; Возврат рез; КонецФункции Функция РазложитьСтрокуВМассивПодстрок(Знач Стр, Разделитель = ",") Экспорт Возврат ОбщегоНазначения.РазложитьСтрокуВМассивПодстрок(Стр,Разделитель); КонецФункции |
|||
4
ejikbeznojek
05.03.18
✎
15:56
|
(3) Угу...сейчас попробую, спасибо.
|
|||
5
ИС-2
naïve
05.03.18
✎
16:05
|
примеры:
ФормироватьПечатнуюФормуПриЗаписи = _ИзмененияКонфигурации.ЗначРекв(Выборка.Ссылка,"ВидПереписки","ФормироватьПечатнуюФормуПриЗаписи"); тест = _ИзмененияКонфигурации.ЗначРекв(Ответственный,"ФизЛицо.ГруппаДоступаФизическогоЛица","Код",Ложь,Неопределено); тест = _ИзмененияКонфигурации.ЗначРекв(Ответственный,"","ФизЛицо.ГруппаДоступаФизическогоЛица.Код",Ложь,Неопределено); тест = _ИзмененияКонфигурации.ЗначРекв(Ответственный,"ФизЛицо","ГруппаДоступаФизическогоЛица.Код",Ложь,Неопределено); тест = _ИзмененияКонфигурации.ЗначРекв(Ответственный,"ФизЛицо.ГруппаДоступаФизическогоЛица.Код","",Ложь,Неопределено); тест = _ИзмененияКонфигурации.ЗначРекв(Ответственный,"ФизЛицо.ГруппаДоступаФизическогоЛица.Код","ГруппаДоступаФизическогоЛица",Ложь,Неопределено); |
|||
6
Cool_Profi
05.03.18
✎
16:12
|
Один раз запросом получи всю тч с нужными реквизитами и ходи по выборке
|
|||
7
unregistered
05.03.18
✎
16:53
|
(6) Перед записью запросом он получит только то, что было в БД раньше (ДО записи). Осмелюсь предположить, что проверяет он то, что в объекте и ещё не записано.
Но в любом случае для толковой оптимизации надо смотреть весь алгоритм проверок. Потому как в зависимости от того что именно и как проверяется необходимо получать все данные для проверок и перебирать ТОЛЬКО их (а не всю табличную часть). |
|||
8
dezm00nd
05.03.18
✎
17:01
|
(7) Надо ТЧ из объекта в ВТ закинуть
|
|||
9
Badjo
05.03.18
✎
17:18
|
(0) Когда ты обращаешься к реквизиту "ссылки" через точку то возможны два варианта:
1. 1С находит по ссылке объект справочника в кеше и берет данные оттуда - всё работает быстро. (Это к тому что если ты будешь смотреть последовательно несколько реквизитов, то падение скорости у тебя будет только на первом обращении к реквизиту ссылки). 2. 1С не находит объект для ссылки в кеше и считывает объект из базы и помещает его в кеш. Соответственно уходит уйма времени на обращение сервера 1С к серверу SQL. У тебя второй вариант еще и в цикле. соответственно тебе нужно избавится от множественных обращений к SQL базе. Ты можешь взять табличную часть документа выгрузить ее таблицу значений (документ же не записан еще). Передать эту ТЗ в запрос и уже в запросе добавить необходимые данные для анализа (либо просто реквизит ВидНоменклатуры, либо через ВЫБОР КОГДА ТОГДА сразу отметить те номенклатуры которые <>Перечисления.ВидыНоменклаутры.ПодарочныйСертификат). Результат запроса выгружаешь в Таблицу значений и проводишь свои манипуляции с данной ТЗ. В конце просто обновляешь табличную часть на таблицу значений через ТабличнаяЧасть.Загрузить(ТЗ). В любом случае всегда старайся оценить приведет ли твой код к обращению к данным SQL или нет. Чем больше раз дернули SQL "по-пустякам" тем "хуже". |
|||
10
NorthWind
05.03.18
✎
22:52
|
(9) +100. Обращение через точку к полям ссылки - тормоз, но это же и очевидно... было бы странно если бы было по-другому.
|
|||
11
Armando
05.03.18
✎
23:41
|
(0) сколько строк в ТЧ обычно?
|
|||
12
ejikbeznojek
05.03.18
✎
23:42
|
(11) 200-300
|
|||
13
Armando
05.03.18
✎
23:44
|
(12) сколько при этом уникальных значений по номенклатуре?
|
|||
14
ejikbeznojek
05.03.18
✎
23:51
|
(5) В общем попробовал.
Если я всё верно понял, то всё сводится к Рез = Вычислить("Источник" + "." +ПутьКРеквизитам); Я не совсем понял разницу между живым и повторным вызовом. Я так понял вся разница только к пути к реквизитам. Прочитав тему по ссылке, я подумал что при живом вызове должен результат кэшироваться, но это видимо просто в кэше при вычислить? Когда я скопипастил в копию базы, и начал получать значения на 1 и тот же документ не перезаходя, а тупо подряд перезаписываю документ. + я был единственным пользователем в базе, я получил странный % выполнения этой строчки Рез = Вычислить("Источник" + "." +ПутьКРеквизитам); 1й раз - 50% 2й раз - 70% 3й раз - 38% 1й раз 50% от времени вы |
|||
15
ejikbeznojek
05.03.18
✎
23:51
|
(13) все уникальные
|
|||
16
ejikbeznojek
05.03.18
✎
23:54
|
(15) внутри 1го дока имеется ввиду.
|
|||
17
Armando
05.03.18
✎
23:59
|
(15) есть возможность этот код выполнять в ПриЗаписи?
Просто 200-300 это многовато, чтоб пихать в параметры запроса, а создавать временную таблицу из табличной части дорого. |
|||
18
ejikbeznojek
06.03.18
✎
00:41
|
(17) Ну у меня сейчас перед записью код из (2) выполняется.
ПриЗаписи мне кажется ничего не изменится. |
|||
19
h-sp
06.03.18
✎
03:22
|
(18) ну так делай
запрос.текст="ВЫБРАТЬ РАЗЛИЧЫЕ | Номенклатура.ВидНоменклатуры как ВидНоменклатуры |ИЗ | Справочник.Номенклатура КАК Номенклатура |ГДЕ | Номенклатура.Ссылка В (&СписокНоменклатуры)"; Запрос.УчтановитьПараметр("СписокНоменклатуры", Товары.ВыгрузитьКолонку("Номенклатура")) у тебя получится не 100 запросов, а один. |
|||
20
rphosts
06.03.18
✎
04:33
|
(2) отбирай всё внутри запроса и само сравнение делай тоже в запросе.
|
|||
21
2mugik
06.03.18
✎
05:16
|
(18)Он тебе намекает что если проверка=ложь редкий случай то можно записать в базу, а потом проверять.
|
|||
22
Адинэснег
06.03.18
✎
08:08
|
(0) запросы в цикле
делай запрос до цикла |
|||
23
lodger
06.03.18
✎
09:10
|
моддим (19)
запрос.текст="ВЫБРАТЬ РАЗЛИЧЫЕ | Номенклатура.Ссылка как Сертификат |ИЗ | Справочник.Номенклатура КАК Номенклатура |ГДЕ | Номенклатура.Ссылка В (&СписокНоменклатуры) |И Номенклатура.ВидНоменклатуры = значение(Перечисление.ВидыНоменклаутры.ПодарочныйСертификат)"; Запрос.УчтановитьПараметр("СписокНоменклатуры", Товары.ВыгрузитьКолонку("Номенклатура")); дописываем в (0) МассивСертификатов = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Сертификат"); Для Каждого СтрокаТЧ Из ДокОбъект.Товары Цикл СтрокаДубля=СтрокиДублей.Получить(СтрокаТЧ.Номенклатура); Если МассивСертификатов.Найти(СтрокаТЧ.Номенклатура) <> Неопределено Тогда ... хэппиэнд |
|||
24
ИС-2
naïve
12.03.18
✎
09:14
|
(14) да, можно получать уже закэшированные значения (из модуля повторного использования) или вычислять вновь. Зависит от вероятности изменения данных. Например, вероятность, что сменится ИНН у контргагента ниже, чем смена контрагента в заказе
|
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |