|
Почему в замере производительности дольше всего выполняется элементарная операция? | ☑ | ||
---|---|---|---|---|
0
anchar007
13.05.21
✎
13:34
|
Оптимизирую самописную внешнюю обработку. Она на основании огромного количества документов за определенный период создаёт новые документы.
В примере на скрине мы создаём новые документы на основании 21000 поступлений и 26000 реализаций, поэтому в некоторые строки мы попадаем по 47000 раз. Скрин: https://ibb.co/8MY5DN3 Почему замер производительности показывает, что элементарная операция сравнения "Если Валюта.Код = "643" Тогда" выполняется в разы дольше, чем например какие-нибудь сложные операции типа запросов, которые вызываются примерно такое же количество раз? Запускал замер производительности уже не один раз и всегда сравнение со строкой самое длительное. |
|||
43
mistеr
13.05.21
✎
14:08
|
(38) Первый раз слышишь про объектный кэш?
|
|||
44
RomanYS
13.05.21
✎
14:09
|
(40) >> А значит кэш очищается.
Вот это я так понимаю теперь очень спорный вопрос. Часть людей считают (я в том числе), что данные кэшируются по ссылке и не умирают в кэше при обновлении переменной. Вторая часть (минимум ты и PR) считают что кэш живёт и умирает вместе с переменной. |
|||
45
mistеr
13.05.21
✎
14:09
|
(40) Значение переменной замещается, а кэш остается в памяти. Если объект не менялся.
|
|||
46
anchar007
13.05.21
✎
14:10
|
Вот весь код:
Функция ПересчитатьВалютнуюСумму(ВалютнаяСумма, Валюта, Дата) Если Валюта = ВалютаРуб Тогда Возврат ВалютнаяСумма; Иначе Возврат ПересчетСуммыПоКурсу(ВалютнаяСумма, Валюта, Дата); КонецЕсли; КонецФункции |
|||
47
mistеr
13.05.21
✎
14:10
|
Этот кэш нужен именно для таких случаев. Обращение к часто используемым объектам из разных мест кода, в разных переменных.
|
|||
48
polosov
13.05.21
✎
14:10
|
(44) Из (37)
"Разумеется, если необходимо многократно обращаться к одному и тому же полю в пределах одного и того же алгоритма, то эффективнее считать данные, запомнить их в переменную и обращаться к уже считанным данным. Но получение данных через ссылку может выдавать ранее считанные данные, даже если они были считаны в другом вызове встроенного языка, так как кэширование выполняется в рамках всей клиентской сессии." |
|||
49
PR
13.05.21
✎
14:10
|
(39) А где ты увидел одни и те же данные? Валюта же меняется в цикле
|
|||
50
H A D G E H O G s
13.05.21
✎
14:10
|
На самом деле, PR тут поднял интересную тему. Которую Печкин не может вкурить.
Запрос.Текст= "Выбрать Номенклатура.Ссылка как Ссылка1, Номенклатура.Ссылка как Ссылка2 Из...." Выборка=Запрос.Выполнить().Выбрать(); Выборка.Следующий(); Ссылка1=Выборка.Ссылка1; Ссылка2=Выборка.Ссылка2; Наименование1=Ссылка1.Наименование; // Будет ли тут использоваться кеш? Наименование2=Ссылка2.Наименование; |
|||
51
RomanYS
13.05.21
✎
14:12
|
(50) я от тебя ответа на (44) ожидал, а для тебя это тоже интересная тема))
|
|||
52
mistеr
13.05.21
✎
14:12
|
(50) Везде будет.
|
|||
53
H A D G E H O G s
13.05.21
✎
14:12
|
(47) "в разных переменных."
Инфа - 100% ? |
|||
54
PR
13.05.21
✎
14:12
|
(40) Это непонятно, да
|
|||
55
mistеr
13.05.21
✎
14:13
|
(49) Через N итераций валюта повторяется.
|
|||
56
H A D G E H O G s
13.05.21
✎
14:13
|
Ща проверим
|
|||
57
azernot
13.05.21
✎
14:13
|
(45) (44) Проведите простой эксперимент.
Сформируйте запрос 40 тыс раз получающий пару валют из справочника, упорядочив по ссылке. И далее, замерьте 2 варианта кода Пока Выборка.Следующий() Цикл Валюта = Выборка.Валюта; Сообщить(Валюта.Код); КонецЦикла; Пока Выборка.Следующий() Цикл Если НЕ Валюта = Выборка.Валюта ТОгда Валюта = Выборка.Валюта; КонецЕсли; Сообщить(Валюта.Код); КонецЦикла; |
|||
58
polosov
13.05.21
✎
14:14
|
(50) Да, будет.
В https://its.1c.ru/db/metod8dev/content/2717/hdoc есть про правильное получение представления. |
|||
59
RomanYS
13.05.21
✎
14:14
|
(56) и про version дай пруф, пожалуйста, если есть под рукой
|
|||
60
mistеr
13.05.21
✎
14:14
|
(57) Сам не хочешь? :)
|
|||
61
PR
13.05.21
✎
14:14
|
(46) Это не может быть всем кодом, потому что ты обращаешься к Валюта, которой нет ни в параметрах ни присвоения раньше
Это же, надеюсь, не реквизит формы? |
|||
62
mistеr
13.05.21
✎
14:15
|
||||
63
PR
13.05.21
✎
14:16
|
(50) Хороший вопрос
И проверяется легко |
|||
64
RomanYS
13.05.21
✎
14:16
|
(62) что-то не то.
|
|||
65
PR
13.05.21
✎
14:17
|
(55) Не уверен, что если ты в переменную записал валюту, которая уже раньше где-то как-то закешировалась, то реквизиты теперь возьмутся из кеша
Опять же, это легко проверяется |
|||
66
mistеr
13.05.21
✎
14:18
|
(64) То самое.
"Если обращаться через ссылки к свойствам одного и того же объекта базы данных, то считывание данных будет происходить только при первом обращении, а так же после того как система выгрузит этот объект из кэша. Данные объекта удерживаются в кэше около 20 минут, но после интервала в 20 секунд при очередном обращении будет выполняться проверка того, что объект в базе данных не менялся, и, при необходимости, выполняется обновление данных в кэше. Если объект записывается в данной сессии, то он сразу обновляется в кэше." |
|||
67
H A D G E H O G s
13.05.21
✎
14:18
|
Да, кешируется, несмотря на разные переменные.
|
|||
68
RomanYS
13.05.21
✎
14:20
|
(67) Ну хоть тут интуиция (и не 1С) не подвела))
|
|||
69
PR
13.05.21
✎
14:20
|
Что-то ТС темнит
|
|||
70
PR
13.05.21
✎
14:21
|
(67) А если валюты одинаковые, но взяты из разных мест, например из разных документов, то есть путь разный?
|
|||
71
H A D G E H O G s
13.05.21
✎
14:21
|
Про повторное считывание - оно считывает Версию раз в 20 секунд. И получает весь пул реквизитов, по условию, отличному от версии:
|
|||
72
H A D G E H O G s
13.05.21
✎
14:21
|
Запрос=Новый Запрос;
Запрос.Текст= "ВЫБРАТЬ | Справочник1.Ссылка КАК Ссылка1, | Справочник1.Ссылка КАК Ссылка2 |ИЗ | Справочник.Справочник1 КАК Справочник1"; Выборка=Запрос.Выполнить().Выбрать(); Выборка.Следующий(); Ссылка1=Выборка.Ссылка1; Ссылка2=Выборка.Ссылка2; Наименование1=Ссылка1.Наименование; Пока Истина Цикл Наименование2=Ссылка2.Наименование; КонецЦикла; |
|||
73
RomanYS
13.05.21
✎
14:21
|
(66) Спасибо. Я "верс", "vers" искал
|
|||
74
anchar007
13.05.21
✎
14:22
|
(61) через ПЕРЕМ объявил переменную ВалютаРуб, записал в неё валюту один раз и потом в цикле к ней обращаюсь
|
|||
75
RomanYS
13.05.21
✎
14:22
|
(70) кэш по ссылке, по фигу откуда тыее берешь
|
|||
76
H A D G E H O G s
13.05.21
✎
14:23
|
||||
77
H A D G E H O G s
13.05.21
✎
14:24
|
Подозреваю, что когда у сервера 1С занятая память подходит к 85% физической, картинка меняется.
|
|||
78
H A D G E H O G s
13.05.21
✎
14:24
|
Сеансовые данные в такой период активно сбрасываются на диск, например.
|
|||
79
RomanYS
13.05.21
✎
14:26
|
(76) Спасибо
|
|||
80
mistеr
13.05.21
✎
14:27
|
Кстати, а транзакций в секретном коде ТС нет ли?
|
|||
81
anchar007
13.05.21
✎
14:29
|
(80) нет, транзакций нет
|
|||
82
BIP1
13.05.21
✎
14:36
|
(81) Покажите код, где вызывается ваша функция ПересчитатьВалютнуюСумму()
|
|||
83
RomanYS
13.05.21
✎
14:41
|
(82) Ага. прикольно будет, если она с клиента контекстным серверным вызовом происходит) За то сразу всё станет на место, даже замер в (25).
|
|||
84
azernot
13.05.21
✎
14:42
|
Выше уже подтвердили, но и я отпишусь.
(60) Я проверил. Вы правы. Данные объекта кэшируются. |
|||
85
Lama12
13.05.21
✎
14:44
|
(74) Толстый клиент? Формы не управляемые?
|
|||
86
VladZ
13.05.21
✎
14:45
|
(0) Потому что потому (с) Сами-знаете-кто.
|
|||
87
mistеr
13.05.21
✎
14:45
|
(83) В замере (0) видно, что все на сервере.
|
|||
88
anchar007
13.05.21
✎
14:54
|
(81) всё на сервере вызывается. Сначала запросом формирую таблицу документов, а потом итерируюсь по этой таблице и выполняю различные действия, в том числе пересчитываю сумму в рубли согласно курсу
(85) управляемые формы |
|||
89
BIP1
13.05.21
✎
15:04
|
Откуда в вашей функции берется значение переменной ВалютаРуб?
ВалютнаяСумма, Валюта, Дата - вы передали в качестве параметров функции. А ВалютаРуб - это что? Функция ПересчитатьВалютнуюСумму(ВалютнаяСумма, Валюта, Дата) Если Валюта = ВалютаРуб Тогда Возврат ВалютнаяСумма; Иначе Возврат ПересчетСуммыПоКурсу(ВалютнаяСумма, Валюта, Дата); КонецЕсли; КонецФункции |
|||
90
Lama12
13.05.21
✎
15:14
|
(89) Меня вот тоже смущает этот момент. Но в (74) сказано что объявил через Перем. Вопрос только, где это объявление и присвоение значения произведено?
|
|||
91
dmpl
13.05.21
✎
15:14
|
(74) Тип переменной какой?
|
|||
92
Lama12
13.05.21
✎
15:16
|
(91) Судя по (25) оба справочник ссылка. Но где в коде эти значения получены, неясно.
|
|||
93
Жан Пердежон
13.05.21
✎
15:30
|
(25) у тебя это сравнение 23тыщи раз выполняется - раздели время на количество и будет < 0,0022 на одну операцию
|
|||
94
anchar007
13.05.21
✎
15:35
|
Перем ВалютаРуб;
(92) Процедура ЗаполнитьТаблицуУслуг(ТаблицаДок) ВалютаРуб = Справочники.Валюты.НайтиПоКоду("643"); Для каждого строка из ТаблицаДок Цикл НоваяСтрокаУслуги = ТаблицаУслуг.Добавить(); НоваяСтрокаДокументы.СуммаПоУслуге = (-1)*ПересчитатьВалютнуюСумму(строка.СуммаУслуги, строка.Документ.ВалютаДокумента, строка.Документ.Дата); КонецЦикла; КонецПроцедуры; |
|||
95
RomanYS
13.05.21
✎
15:36
|
(94) строка.Документ.ВалютаДокумента - это ппц
|
|||
96
RomanYS
13.05.21
✎
15:39
|
(87) строго говоря, видно что эта строка выполняется на сервере. Откуда вызвана функция мы не видим.
Но проверил, расходы на передачу контекста в отладке показываются в строке вызова функции (а не на её первую строку) - моё предположение в (83) не могло быть верным при таком замере |
|||
97
anchar007
13.05.21
✎
15:41
|
(93) но в любом случае сравнение двух переменных должно выполняться в разы быстрее, чем например запрос.
В строке 521 запрос вызывается 11826 раз (в 2 раза реже. чем сравнение двух переменных). А выполняется он в 7 раз быстрее. В строке 267 я 23 тыс. раз ищу элементы справочника номенклатурные группы по наименованию. Очевидно, что процедура поиска по значению в разы медленнее, чем процедура сравнения двух ссылок. Но однако она тоже выполняется примерно в 7 раз быстрее. |
|||
98
H A D G E H O G s
13.05.21
✎
15:42
|
(97) Ты где то ошибся в замере.
|
|||
99
BIP1
13.05.21
✎
15:43
|
(97) а теперь замените строку "строка.Документ.ВалютаДокумента" на "ВалютаДокумента", а переменной ВалютаДокумента присвойте значение ВалютаДокумента = строка.Документ.ВалютаДокумента чуть выше.
И запустить замер снова. |
|||
100
Жан Пердежон
13.05.21
✎
15:43
|
(94) всё равно говнокод)
|
|||
101
ptiz
13.05.21
✎
15:43
|
(0) Либо ошибка в замере, либо вы в справочник Валюты запихнули реквзит типа ХранилищеЗначений для картинок.
|
|||
102
Жан Пердежон
13.05.21
✎
15:44
|
(97) а что там за запрос?
|
|||
103
BIP1
13.05.21
✎
15:45
|
(99) про качество кода, вам уже написали.
Получайте всё, что можно В ЗАПРОСЕ, а не через извраты вида Строка.Документ.ИмяРеквизита. |
|||
104
polosov
13.05.21
✎
15:45
|
Явно проблема в "строка.Документ.ВалютаДокумента"
Замер просто не правильно отображает похоже. |
|||
105
polosov
13.05.21
✎
15:50
|
(97) Теоретически, если ты в ПересчитатьВалютнуюСумму()
Поставишь в начале А = 1; То замер укажет на эту строку, как на наиболее жручую. |
|||
106
anchar007
13.05.21
✎
16:02
|
(99) и правда причина была в строка.Документ.ВалютаДокумента
Я думал, что если на вход в функцию ПересчитатьВалютнуюСумму передать две ссылки и их сравнить, то нет разницы каким образом эти ссылки были получены. А оказывается разница есть |
|||
107
anchar007
13.05.21
✎
16:06
|
(103) Понятно, что в можно переписать запрос и пересчитывать сумму в рубли уже в запросе.
Не понятно было почему замер производительности грешит на казалось бы простейшую операцию сравнения двух значений с одинаковым типом |
|||
108
pechkin
13.05.21
✎
16:06
|
(106) еще и дата получается
|
|||
109
anchar007
13.05.21
✎
16:08
|
(108) получается да. Она не попадала в замер производительности, так как валютных операций не много
|
|||
110
BIP1
13.05.21
✎
16:10
|
(107) Он не на неё грешил, а на Строка.Документ.ВалютаДокумента. Нам же значение параметра ВалютаДокумента требуется только в момент проверки условия, вот он и получает это значение в момент проверки условия, а не при вызове функции. Вдруг, например, нам это значение в функции нигде и не пригодится. Зачем лишний раз что-то считать? Ленивые вычисления
|
|||
111
BIP1
13.05.21
✎
16:11
|
Сделайте замер цикла от 1 по 1000000 с 1 условием:
Если ИСТИНА ИЛИ Строка.Документ.ВалютаДокумента = Рубли Тогда КонецЕсли; А потом тоже самое с таким кодом: Если ЛОЖЬ ИЛИ Строка.Документ.ВалютаДокумента = Рубли Тогда КонецЕсли; Результаты замеров будут разные |
|||
112
Lama12
13.05.21
✎
16:35
|
(111) :-D ну да, ИСТИНА выполняется быстрее чем ЛОЖЬ.
|
|||
113
mistеr
13.05.21
✎
16:40
|
(107) Если действительно хочешь понять, показывай полный код.
|
|||
114
BIP1
13.05.21
✎
16:43
|
(112) потому что зачем выполнять вторую половину условия, если результат будет и так и так ИСТИНА.
При оптимизации кода можно всякие "тяжелые" вычисления в "длинных" условиях стараться отодвигать как можно дальше, чтобы системе их считать приходилось как можно реже. Но кто будет с таким заморачиваться🤷♂️ |
|||
115
Kassern
13.05.21
✎
16:44
|
(114) это же вроде в одних из первых занятиях по 1с рассказывают...
|
|||
116
azernot
13.05.21
✎
16:45
|
Во всех конфах на БСП есть функция типа ЗначенияРеквизитовОбъекта.
Каждый раз, когда возникает желание получать реквизит ссылки, нужно вспоминать об этой процедуре. Т.е. к примеру делать так: СтруктураРеквизитовДокумента = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(строка.Документ, "ВалютаДокумента, Дата") НоваяСтрокаДокументы.СуммаПоУслуге = (-1)*ПересчитатьВалютнуюСумму(строка.СуммаУслуги, СтруктураРеквизитовДокумента.ВалютаДокумента, СтруктураРеквизитовДокумента.Дата); |
|||
117
mistеr
13.05.21
✎
16:47
|
(110) Похоже на правду
|
|||
118
Lama12
13.05.21
✎
16:47
|
(115) Это даже в справке, встроенной написано.
|
|||
119
mistеr
13.05.21
✎
16:48
|
(116) Этот позор архитектуры давно пора спрятать в платформу.
|
|||
120
azernot
13.05.21
✎
16:49
|
(119) Кто ж спорит, но пока есть, что есть.
|
|||
121
RomanYS
13.05.21
✎
16:53
|
(116) в данном случае глобально это картину не сильно изменит - всё равно 40к запросов к базе (только они чуть полегче). Эти данные безусловно должны быть в самой таблице
|
|||
122
polosov
13.05.21
✎
16:54
|
(119) Тогда неучи его будут использовать как в (116)
По всем нужным документам одним запросом надо получить данные и потом использовать в своем цикле. |
|||
123
Bigbro
13.05.21
✎
17:25
|
27 тысяч запросов в цикле.. еще бы было быстро
|
|||
124
pechkin
13.05.21
✎
17:27
|
ну если нужно 27 тыщ документов записать, то и поболее запросов будет
|
|||
125
mistеr
13.05.21
✎
17:32
|
(122) Да, но платформа вполне способна проанализировать их цикл, собрать все используемые реквизиты и получить их неявно.
|
|||
126
RomanYS
13.05.21
✎
17:42
|
(125) платформа с телепатией это круто, но пока только боты.
|
|||
127
BIP1
13.05.21
✎
18:08
|
(126) https://ibb.co/3vfvRRx
|
|||
128
PR
13.05.21
✎
18:10
|
(119), (120), вы такие милые со своими авторитетными доморощенными мнениями, прямо ми-ми-ми
Прямо фузиной немножечко пахнуло |
|||
129
polosov
13.05.21
✎
18:13
|
(125) Это слишком сложно и не нужно.
|
|||
130
Dmitrii
гуру
13.05.21
✎
18:39
|
(111) >> Результаты замеров будут разные.
Это очевидно. Для этого даже сам замер делать не нужно. Только каким боком данный пример относится к обсуждению? |
|||
131
DmVl76
14.05.21
✎
06:16
|
(97) Кстати, а почему столько запросов в цикле. Судя по всему, по каждому документу запрос. Может сделать выборку одним запросом?
|
|||
132
DimVad
14.05.21
✎
07:42
|
(111) Прошу прощения, но подозреваю что в условии :
Если ИСТИНА ИЛИ Строка.Документ.ВалютаДокумента = Рубли Тогда КонецЕсли; Выражение "Строка.Документ.ВалютаДокумента = Рубли" вообще вычисляться не будет. Самое простое - пусть второе выражение после "ИЛИ" содержит ошибку (типа, ЗначениеЗаполнено на мутабельное). Если впереди ИСТИНА - пройдёт со свистом. ЛОЖЬ - вылетит. |
|||
133
DimVad
14.05.21
✎
07:48
|
Кстати, если хочется получить значение через ссылку но лень писать запрос то есть же:
Код_ = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(МояСсыль, "Код"); Структура_ = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(МояСсыль, "Код, Наименование"); |
|||
134
ДенисЧ
14.05.21
✎
07:49
|
(133) А там типа не запросы...
|
|||
135
DimVad
14.05.21
✎
07:51
|
(134) Но их не надо писать... :)
Не, если можно получить заранее один раз - то надо сохранить в переменную, без базара. "ЗначениеРеквизитаОбъекта" спасает от загрузки лишней информации при получении данных через ссылку. |
|||
136
BIP1
14.05.21
✎
10:07
|
(132) Конечно. Просто этот пример в рамках обсуждаемого контекста, так сказать "в моменте", не более того. Если абстрактно "в вакууме" такие примеры показывать, то можно было и так: "ИСТИНА ИЛИ 1/0 = 1" vs "ЛОЖЬ ИЛИ 1/0 = 1"
|
|||
137
rozer76
14.05.21
✎
11:45
|
(37) вот никогда не понимал а почему в теч 20сек 1с не проверяет версию объекта а выдает из кеша ?
https://its.1c.ru/db/pubdevguide83#content:303:hdoc |
|||
138
timurhv
14.05.21
✎
11:59
|
(5) На больших данных это долго работает в циклах. Оптимизировал условие через булево, условно:
"Если ЭтоВалютаРуб Тогда" с помощью запроса, скорость проведения стала 7 сек вместо 11. |
|||
139
mistеr
14.05.21
✎
13:59
|
(137) Чтобы кэширование имело хоть какой-то смысл.
|
|||
140
pechkin
14.05.21
✎
14:05
|
(137) так версию нужно же в бд получать
|
|||
141
Garikk
14.05.21
✎
14:12
|
(137)(139) <Если окажется, что версии данных не совпадают (т. е. произошло изменение данных в базе данных), данные, находящиеся в кеше, будут удалены из него, и будет выполнено повторное считывание данных из базы данных. Начиная с этого момента, идет отсчет следующего 20-секундного интервала валидности этих данных.>
вы точно читаете всё что цитируете? |
|||
142
rozer76
14.05.21
✎
17:16
|
(141) ага, если данные изменились в 19ую секунду то 1с возмет их из кеша а не бд а это уже фейл (
|
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |