Вход | Регистрация


1С:Предприятие :: 1С:Предприятие 8 общая

Обращение к реквизиту справочника через точку

Обращение к реквизиту справочника через точку
Я
   ejikbeznojek
 
05.03.18 - 15:42
Всем привет.
Есть нетиповая конфа на 8.1
Есть документ с табличной частью.
Перед записью документа есть цикл по этой ТЧ, в которой происходит ряд проверок.

[code]
Для Каждого СтрокаТЧ Из ДокОбъект.Товары Цикл
СтрокаДубля=СтрокиДублей.Получить(СтрокаТЧ.Номенклатура);
Если СтрокаТЧ.Номенклатура.ВидНоменклатуры<>Перечисления.ВидыНоменклаутры.ПодарочныйСертификат Тогда

Замер производительности показывает, что это условие выполняется около 30% времени от всей операции по записи и проведению документа.

ВидНоменклатуры это не составной реквизит с типом значения - перечисление. Индексировать не стоит, но я пробовал поставить это ничего не дало. Если переделать на запрос, тогда будет 7% процентов вместо 30, но я как-то ожидаю увидеть меньше 0,1%.

В чём может быть дело?

[/code]
 
 
   hhhh
 
1 - 05.03.18 - 15:48
(0) запрос в студию
   ejikbeznojek
 
2 - 05.03.18 - 15:51
https://prnt.sc/in3bi9
Пробовал переделывать
с 
Если СтрокаТЧ.Номенклатура.ВидНоменклатуры<>Перечисления.ВидыНоменклаутры.ПодарочныйСертификат Тогда

на
            запрос.текст="ВЫБРАТЬ
            |    Номенклатура.ВидНоменклатуры как ВидНоменклатуры
            |ИЗ
            |    Справочник.Номенклатура КАК Номенклатура
            |ГДЕ
            |    Номенклатура.Ссылка = &Ссылка";
если запрос.выполнить.выгрузить().получить(0).ВидНоменклатуры<>Перечисления.ВидыНоменклаутры.ПодарочныйСертификат Тогда
   ИС-2
 
3 - 05.03.18 - 15:53
текст вопроса как у меня - почти 1 в один:

Оптимизация обращений к реквизитам объектов через точку
Оптимизация обращений к реквизитам объектов через точку

написал функцию
Функция ЗначРекв(Источник, ПутьКРеквизитамПовтИсп,ПутьКРеквизитамЖивым = "",ОбновитьПовтИсп = Ложь,ДопПараметры = Неопределено) Экспорт 
    ЧерезПовтИсп = Ложь;
    ТипИсточника = ТипЗнч(Источник);
    // объекты нельзя передавать в модуль повторного использования

    Если Документы.ТипВсеСсылки().СодержитТип(ТипИсточника) Тогда 
        ЧерезПовтИсп = Истина;
    ИначеЕсли Перечисления.ТипВсеСсылки().СодержитТип(ТипИсточника) Тогда 
        ЧерезПовтИсп = Истина;
    ИначеЕсли Справочники.ТипВсеСсылки().СодержитТип(ТипИсточника) Тогда 
        ЧерезПовтИсп = Истина;    
    КонецЕсли;
    
    // надо получить все актуальные данные

    Если ПутьКРеквизитамПовтИсп = "" Тогда 
        ЧерезПовтИсп = Ложь;    
    КонецЕсли;    
    
    Если ЧерезПовтИсп Тогда 
        СтрокаВызоваПовтИсп = "";
        СтрокаВызоваЖивогоВызова = "";
        ИмяЖивогоРеквизита = "";
        
        МассивРеквзитов = _ПовтИсп.РазложитьСтрокуВМассивПодстрок(ПутьКРеквизитамПовтИсп,".");
        МассивРеквзитовЖивых = _ПовтИсп.РазложитьСтрокуВМассивПодстрок(ПутьКРеквизитамЖивым,".");
        
        // все, что после 1-го живого реквизита получаем из актуальных данных

        Если МассивРеквзитовЖивых.Количество() > 0 Тогда 
            ИмяЖивогоРеквизита = МассивРеквзитовЖивых[0];
        КонецЕсли;    
        
        // признак, что все последубщие данные надо брать из актуальных данных

        ВЖивойВызов = Ложь;
        Для Каждого ТекРеквизит из МассивРеквзитов Цикл 
            Если ТекРеквизит = ИмяЖивогоРеквизита Тогда 
                ВЖивойВызов = Истина;
                СтрокаВызоваЖивогоВызова = СтрокаВызоваЖивогоВызова + ?(СтрокаВызоваЖивогоВызова = "","",".") + ТекРеквизит;
            ИначеЕсли не ВЖивойВызов Тогда     
                СтрокаВызоваПовтИсп = СтрокаВызоваПовтИсп + ?(СтрокаВызоваПовтИсп = "","",".") + ТекРеквизит;
            иначе
                СтрокаВызоваЖивогоВызова = СтрокаВызоваЖивогоВызова + ?(СтрокаВызоваЖивогоВызова = "","",".") + ТекРеквизит;;
            КонецЕсли;
        КонецЦикла;    
        
        если не СтрокаВызоваПовтИсп = "" Тогда 
            Рез = _ПовтИсп.ЗначРекв(Источник, СтрокаВызоваПовтИсп,ДопПараметры);
        КонецЕсли;
        
        если не ПутьКРеквизитамЖивым = "" 
            // передан реквзит после которого не надо вычислять

            и не ВЖивойВызов
            Тогда 
            СтрокаВызоваЖивогоВызова = СтрокаВызоваЖивогоВызова + ?(СтрокаВызоваЖивогоВызова = "","",".") + ПутьКРеквизитамЖивым;
        КонецЕсли;    
            
        Если не СтрокаВызоваЖивогоВызова = ""
            //  это составной тип

            и не Рез = Неопределено
            Тогда 
            Рез = Вычислить("Рез"+"." + СтрокаВызоваЖивогоВызова);
        КонецЕсли;
    иначе
        СтрокаВызоваЖивогоВызова = ПутьКРеквизитамПовтИсп;
        Если не ПутьКРеквизитамЖивым = ""
            Тогда 
            СтрокаВызоваЖивогоВызова =  ?(СтрокаВызоваЖивогоВызова = "","",".") + ПутьКРеквизитамЖивым;
        КонецЕсли;
        Рез = Вычислить("Источник" + "." + СтрокаВызоваЖивогоВызова);
    КонецЕсли;
    
    Возврат Рез;
КонецФункции

в модуле _ПовтИсп:

Функция ЗначРекв(Источник, ПутьКРеквизитам,ДопПараметры) Экспорт 
    Реквзиты = РазложитьСтрокуВМассивПодстрок(ПутьКРеквизитам,".");
    Если Реквзиты.количество() = 0 Тогда 
        Рез = Источник;
    иначе
        Рез = Вычислить("Источник" + "." +ПутьКРеквизитам);
    КонецЕсли;
    
    Возврат рез;
КонецФункции

Функция РазложитьСтрокуВМассивПодстрок(Знач Стр, Разделитель = ",") Экспорт 
    Возврат ОбщегоНазначения.РазложитьСтрокуВМассивПодстрок(Стр,Разделитель);
КонецФункции
   ejikbeznojek
 
4 - 05.03.18 - 15:56
(3) Угу...сейчас попробую, спасибо.
   ИС-2
 
5 - 05.03.18 - 16:05
примеры:
            ФормироватьПечатнуюФормуПриЗаписи = _ИзмененияКонфигурации.ЗначРекв(Выборка.Ссылка,"ВидПереписки","ФормироватьПечатнуюФормуПриЗаписи"); 

    тест = _ИзмененияКонфигурации.ЗначРекв(Ответственный,"ФизЛицо.ГруппаДоступаФизическогоЛица","Код",Ложь,Неопределено);
    тест = _ИзмененияКонфигурации.ЗначРекв(Ответственный,"","ФизЛицо.ГруппаДоступаФизическогоЛица.Код",Ложь,Неопределено);
    тест = _ИзмененияКонфигурации.ЗначРекв(Ответственный,"ФизЛицо","ГруппаДоступаФизическогоЛица.Код",Ложь,Неопределено);
    тест = _ИзмененияКонфигурации.ЗначРекв(Ответственный,"ФизЛицо.ГруппаДоступаФизическогоЛица.Код","",Ложь,Неопределено);
    тест = _ИзмененияКонфигурации.ЗначРекв(Ответственный,"ФизЛицо.ГруппаДоступаФизическогоЛица.Код","ГруппаДоступаФизическогоЛица",Ложь,Неопределено);
   Cool_Profi
 
6 - 05.03.18 - 16:12
Один раз запросом получи всю тч с нужными реквизитами и ходи по выборке
   unregistered
 
7 - 05.03.18 - 16:53
(6) Перед записью запросом он получит только то, что было в БД раньше (ДО записи). Осмелюсь предположить, что проверяет он то, что в объекте и ещё не записано.

Но в любом случае для толковой оптимизации надо смотреть весь алгоритм проверок. Потому как в зависимости от того что именно и как проверяется необходимо получать все данные для проверок и перебирать ТОЛЬКО их (а не всю табличную часть).
   dezm00nd
 
8 - 05.03.18 - 17:01
(7) Надо ТЧ из объекта в ВТ закинуть
   Badjo
 
9 - 05.03.18 - 17:18
(0) Когда ты обращаешься к реквизиту "ссылки" через точку то возможны два варианта:
1. 1С находит по ссылке объект справочника в кеше и берет данные оттуда - всё работает быстро. (Это к тому что если ты будешь смотреть последовательно несколько реквизитов, то падение скорости у тебя будет только на первом обращении к реквизиту ссылки).
2. 1С не находит объект для ссылки в кеше и считывает объект из базы и помещает его в кеш. Соответственно уходит уйма времени на обращение сервера 1С к серверу SQL.

У тебя второй вариант еще и в цикле.

соответственно тебе нужно избавится от множественных обращений к SQL базе. Ты можешь взять табличную часть документа выгрузить ее таблицу значений (документ же не записан еще). Передать эту ТЗ в запрос и уже в запросе добавить необходимые данные для анализа (либо просто реквизит ВидНоменклатуры, либо через ВЫБОР КОГДА ТОГДА сразу отметить те номенклатуры которые <>Перечисления.ВидыНоменклаутры.ПодарочныйСертификат).
Результат запроса выгружаешь в Таблицу значений и проводишь свои манипуляции с данной ТЗ.
В конце просто обновляешь табличную часть на таблицу значений через ТабличнаяЧасть.Загрузить(ТЗ).

В любом случае всегда старайся оценить приведет ли твой код к обращению к данным SQL или нет. Чем больше раз дернули SQL "по-пустякам" тем "хуже".
   NorthWind
 
10 - 05.03.18 - 22:52
(9) +100. Обращение через точку к полям ссылки - тормоз, но это же и очевидно... было бы странно если бы было по-другому.
 
 Рекламное место пустует
   Armando
 
11 - 05.03.18 - 23:41
(0) сколько строк в ТЧ обычно?
   ejikbeznojek
 
12 - 05.03.18 - 23:42
(11) 200-300
   Armando
 
13 - 05.03.18 - 23:44
(12) сколько при этом уникальных значений по номенклатуре?
   ejikbeznojek
 
14 - 05.03.18 - 23:51
(5) В общем попробовал.
Если я всё верно понял, то всё сводится к
Рез = Вычислить("Источник" + "." +ПутьКРеквизитам); 
Я не совсем понял разницу между живым и повторным вызовом.
Я так понял вся разница только к пути к реквизитам. Прочитав тему по ссылке, я подумал что при живом вызове должен результат кэшироваться, но это видимо просто в кэше при вычислить?

Когда я скопипастил в копию базы, и начал получать значения на 1 и тот же документ не перезаходя, а тупо подряд перезаписываю документ. + я был единственным пользователем в базе, я получил странный % выполнения этой строчки Рез = Вычислить("Источник" + "." +ПутьКРеквизитам);
1й раз - 50%
2й раз - 70%
3й раз - 38%
1й раз 50% от времени вы
   ejikbeznojek
 
15 - 05.03.18 - 23:51
(13) все уникальные
   ejikbeznojek
 
16 - 05.03.18 - 23:54
(15) внутри 1го дока имеется ввиду.
   Armando
 
17 - 05.03.18 - 23:59
(15) есть возможность этот код выполнять в ПриЗаписи?
Просто 200-300 это многовато, чтоб пихать в параметры запроса, а создавать временную таблицу из табличной части дорого.
   ejikbeznojek
 
18 - 06.03.18 - 00:41
(17) Ну у меня сейчас перед записью код из  (2)  выполняется.
ПриЗаписи мне кажется ничего не изменится.
   h-sp
 
19 - 06.03.18 - 03:22
(18) ну так делай
 запрос.текст="ВЫБРАТЬ РАЗЛИЧЫЕ
            |    Номенклатура.ВидНоменклатуры как ВидНоменклатуры 
            |ИЗ
            |    Справочник.Номенклатура КАК Номенклатура
            |ГДЕ
            |    Номенклатура.Ссылка В (&СписокНоменклатуры)";

Запрос.УчтановитьПараметр("СписокНоменклатуры", Товары.ВыгрузитьКолонку("Номенклатура"))


у тебя получится не 100 запросов, а один.
   rphosts
 
20 - 06.03.18 - 04:33
(2) отбирай всё внутри запроса и само сравнение делай тоже в запросе.
   2mugik
 
21 - 06.03.18 - 05:16
(18)Он тебе намекает что если проверка=ложь редкий случай то можно записать в базу, а потом проверять.
   Адинэснег
 
22 - 06.03.18 - 08:08
(0) запросы в цикле
делай запрос до цикла
   lodger
 
23 - 06.03.18 - 09:10
моддим (19) 

запрос.текст="ВЫБРАТЬ РАЗЛИЧЫЕ 
            |    Номенклатура.Ссылка как Сертификат
            |ИЗ
            |    Справочник.Номенклатура КАК Номенклатура
            |ГДЕ
            |    Номенклатура.Ссылка В (&СписокНоменклатуры)
            |И Номенклатура.ВидНоменклатуры = значение(Перечисление.ВидыНоменклаутры.ПодарочныйСертификат)";

Запрос.УчтановитьПараметр("СписокНоменклатуры", Товары.ВыгрузитьКолонку("Номенклатура"));

дописываем в (0)

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

... хэппиэнд
   ИС-2
 
24 - 12.03.18 - 09:14
(14) да, можно получать уже закэшированные значения (из модуля повторного использования) или вычислять вновь. Зависит от вероятности изменения данных. Например, вероятность, что сменится ИНН у контргагента ниже, чем смена контрагента в заказе


Список тем форума
Рекламное место пустует  Рекламное место пустует
ВНИМАНИЕ! Если вы потеряли окно ввода сообщения, нажмите Ctrl-F5 или Ctrl-R или кнопку "Обновить" в браузере.
Тема не обновлялась длительное время, и была помечена как архивная. Добавление сообщений невозможно.
Но вы можете создать новую ветку и вам обязательно ответят!
Каждый час на Волшебном форуме бывает более 2000 человек.
Рекламное место пустует