powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Обращение к полям элемента коллекции большого размера, напрямую или через копию элемента?
13 сообщений из 13, страница 1 из 1
Обращение к полям элемента коллекции большого размера, напрямую или через копию элемента?
    #40049179
anvano
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дано некоторая коллекция (допустим на миллион элементов).
У каждого элемента коллекции приличное количество полей.

При обработке данной коллекции в цикле, как выгоднее обращаться к полям каждой отдельной строки?
Напрямую для каждого поля обращаясь к элементу коллекции (столько раз, сколько полей):
Код: plsql
1.
2.
3.
4.
  
t_row(i).field1 
t_row(i).field2
t_row(i).field3 



Или сделать копию строки, а потом обращаться уже к полям этой переменной?
Код: plsql
1.
2.
3.
4.
5.
  
r_row := t_row(i)
r_row.field1 
r_row.field2
r_row.field3 




--------------------------------------------------------------
Запомните, товарищи офицеры, чтобы ничего не делать, надо уметь делать все.
...
Рейтинг: 0 / 0
Обращение к полям элемента коллекции большого размера, напрямую или через копию элемента?
    #40049189
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
anvano
Дано некоторая коллекция (допустим на миллион элементов).
У каждого элемента коллекции приличное количество полей.

это плохая история. И, чем "свежее" версия системы, тем, по вероятности, хуже...

anvanoИли сделать копию строки, а потом обращаться уже к полям этой переменной?
Код: plsql
1.
2.
3.
4.
5.
  
r_row := t_row(i)
r_row.field1 
r_row.field2
r_row.field3 




здесь вы точно попадаете на "сделать копию".
Вы не забыли, что у вас "У каждого элемента коллекции приличное количество полей."?
В цикле вы гарантированно произведете копирование объемом, грубо, примерно в полный объем памяти, занимаемой коллекцией.


anvanoНапрямую для каждого поля обращаясь к элементу коллекции (столько раз, сколько полей):
Код: plsql
1.
2.
3.
4.
  
t_row(i).field1 
t_row(i).field2
t_row(i).field3 




Здесь на копирование вы не попадаете, но попадаете на многократный косвенный доступ.
Для широких коллекций это, по вероятности, всё-таки предпочтительней.

Есть такого рода "третий вариант":
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
  
  type t_widerow_r is Record(Fld1 Number,... Fldk Number);
  type t_wide_pltable is table of t_widerow_r index by pls_integer;

  Procedure process_wide_row(p_row in out nocopy t_widerow_r)
Is
Begin
  ... p_row.Fld1...
  ... p_row.Fldk...
End;
...
  For i in a_wide.First..a_wide.Last
  Loop
    process_wide_row(a_wide(i));
  End Loop;



Он точно удобнее множественный индексных обращений,
для in-параметра обычно по скорости он не хуже прямого индексированного обращения.
Для in out nocopy - без гарантий, но, как правило, работает.
...
Рейтинг: 0 / 0
Обращение к полям элемента коллекции большого размера, напрямую или через копию элемента?
    #40049193
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
booby
Код: plsql
1.
2.
3.
  Procedure process_wide_row(p_row in out nocopy t_widerow_r)
...
    process_wide_row(a_wide(i));

Выделенное можно смело выбросить без какого-либо влияния на "производительность".
...
Рейтинг: 0 / 0
Обращение к полям элемента коллекции большого размера, напрямую или через копию элемента?
    #40049194
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
anvano
Или сделать копию строки, а потом обращаться уже к полям этой переменной?
Я склонен считать, что так быстрее (и читабельней).
А что тебе мешает поставить эксперимент с замером времени?
...
Рейтинг: 0 / 0
Обращение к полям элемента коллекции большого размера, напрямую или через копию элемента?
    #40049195
anvano
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
booby

здесь вы точно попадаете на "сделать копию".
Вы не забыли, что у вас "У каждого элемента коллекции приличное количество полей."?
В цикле вы гарантированно произведете копирование объемом, грубо, примерно в полный объем памяти, занимаемой коллекцией.


Ну переменная r_row одна же.
Прям при каждой итерации цикла будет заново память выделяться под r_row?
А предыдущая память куда деваться будет?

Я вот собственно поэтому и спрашиваю, что будет профитнее.
Один раз скопировать элемент и потом обращаться к полям копии.
Или лазить в коллекцию по индексу столько раз, сколько полей в коллекции.

Мне почему-то не кажется, что при "копировании" после цикла мы получим две копии коллекции в памяти.
Не может же настолько тупо работать с памятью оракл.
...
Рейтинг: 0 / 0
Обращение к полям элемента коллекции большого размера, напрямую или через копию элемента?
    #40049196
anvano
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Elic
anvano
Или сделать копию строки, а потом обращаться уже к полям этой переменной?
Я склонен считать, что так быстрее (и читабельней).
А что тебе мешает поставить эксперимент с замером времени?


Попробую еще раз поэкспериментировать.
Но у меня почему-то странные результаты получались, видимо из-за каких-то оптимизаций - время сильно зависело от того какой пример прогоняется "первым". С копированием или без.
...
Рейтинг: 0 / 0
Обращение к полям элемента коллекции большого размера, напрямую или через копию элемента?
    #40049197
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
anvano
Прям при каждой итерации цикла будет заново память выделяться под r_row?
Болтун имел в виду, что прокачаешь всю коллекцию через "щелку" переменной.
Почему ему невдомёк, что то же объём прокачается и поэлементно, не берусь судить.

anvano
Но у меня почему-то странные результаты получались, видимо из-за каких-то оптимизаций - время сильно зависело от того какой пример прогоняется "первым". С копированием или без.
А ты предоставь свой скрипт. Мы поможем тебе его правильно отхронометрировать.
...
Рейтинг: 0 / 0
Обращение к полям элемента коллекции большого размера, напрямую или через копию элемента?
    #40049201
anvano
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ниже скрипт, который получится у меня для теста на пару миллионов записей

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
mem=1,97          -- До инициализации коллекции
mem=2070,66    -- После инициализации коллекции 

mem1=2070,66
+000000000 00:00:04.384097000   -- вариант  без копирования

mem2=2070,66
+000000000 00:00:04.659616000   -- вариант с копированием

При перестановке тестов местами - время такое же, т.е. я был не прав, что зависит от этого.
Получается, что без копирования быстрее, но не прям чтобы "ужас-ужас".
Потребление памяти после цикла "с копированием" ожидаемо не выросло.

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

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
DECLARE
   TYPE typ_rec IS RECORD(
     n1  NUMBER,n2  NUMBER,n3  NUMBER,n4  NUMBER,n5  NUMBER,n6  NUMBER,n7  NUMBER,n8  NUMBER,n9  NUMBER,
     s1  VARCHAR2(1000), s2  VARCHAR2(1000),s3  VARCHAR2(1000),s4  VARCHAR2(1000),s5  VARCHAR2(1000),s6  VARCHAR2(1000),
     d1  DATE, d2  DATE,d3  DATE,d4  DATE, d5  DATE, d6  DATE, d7  DATE, d8  DATE
   );
   TYPE typ_tbl IS TABLE OF typ_rec INDEX BY PLS_INTEGER;
   t_row typ_tbl;
   r_row typ_rec;
   tmp   VARCHAR2(4000);
   strt  TIMESTAMP; 
   
  FUNCTION get_mem RETURN NUMBER IS
    l_res NUMBER;
  BEGIN
    SELECT round(sum(ms.VALUE) / 1024 /1024,2) INTO l_res
    from v$statname sn, v$mystat ms
    where sn.name = 'session pga memory' and ms.STATISTIC# = sn.STATISTIC#
    order by sn.NAME;
    RETURN l_res;    
  END;  
   
BEGIN
   r_row.n1 := 1;
   r_row.n2 := 2;
   r_row.n3 := 3;
   r_row.n4 := 4;
   r_row.n5 := 5;
   r_row.n6 := 6;
   r_row.n7 := 7;
   r_row.n8 := 8;
   r_row.n9 := 9;
   r_row.s1 := 's1';
   r_row.s2 := 's2';
   r_row.s3 := 's3';
   r_row.s4 := 's4';
   r_row.s5 := 's5';
   r_row.s6 := 's6';
   r_row.d1 := SYSDATE;
   r_row.d2 := SYSDATE;
   r_row.d3 := SYSDATE;
   r_row.d4 := SYSDATE;
   r_row.d5 := SYSDATE;
   r_row.d6 := SYSDATE;
   r_row.d7 := SYSDATE;
   r_row.d8 := SYSDATE;
   
   dbms_output.put_line('mem='||get_mem); 
   FOR i IN 1..2000000 LOOP
     t_row(i) := r_row;
   END LOOP;  
   dbms_output.put_line('mem='||get_mem); 
   

   strt := SYSTIMESTAMP;
   FOR i IN 1..t_row.count LOOP
      tmp := t_row(i).n1||t_row(i).n2||t_row(i).n3||t_row(i).n4||t_row(i).n5||t_row(i).n6||t_row(i).n7||t_row(i).n8||t_row(i).n9
        ||t_row(i).s1||t_row(i).s2||t_row(i).s3||t_row(i).s4||t_row(i).s5||t_row(i).s6
        ||t_row(i).d1||t_row(i).d2||t_row(i).d3||t_row(i).d4||t_row(i).d5||t_row(i).d6||t_row(i).d7||t_row(i).d8;
   END LOOP;            
   dbms_output.put_line('mem1='||get_mem); 
   dbms_output.put_line(SYSTIMESTAMP - strt); 
   
     
   strt := SYSTIMESTAMP;
   FOR i IN 1..t_row.count LOOP
      r_row := t_row(i);
      tmp := r_row.n1||r_row.n2||r_row.n3||r_row.n4||r_row.n5||r_row.n6||r_row.n7||r_row.n8||r_row.n9
        ||r_row.s1||r_row.s2||r_row.s3||r_row.s4||r_row.s5||r_row.s6
        ||r_row.d1||r_row.d2||r_row.d3||r_row.d4||r_row.d5||r_row.d6||r_row.d7||r_row.d8;
   END LOOP;  
   dbms_output.put_line('mem2='||get_mem); 
   dbms_output.put_line(SYSTIMESTAMP - strt); 
END;
...
Рейтинг: 0 / 0
Обращение к полям элемента коллекции большого размера, напрямую или через копию элемента?
    #40049202
anvano
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Кстати вариант с вызовом процедуры:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
  PROCEDURE process_wide_row(r IN OUT NOCOPY typ_rec) IS
  BEGIN
      tmp := r.n1||r.n2||r.n3||r.n4||r.n5||r.n6||r.n7||r.n8||r.n9
        ||r.s1||r.s2||r.s3||r.s4||r.s5||r.s6
        ||r.d1||r.d2||r.d3||r.d4||r.d5||r.d6||r.d7||r.d8;
  END;    


..................
   strt := SYSTIMESTAMP;
   FOR i IN 1..t_row.count LOOP
      process_wide_row(t_row(i));
   END LOOP;  
   dbms_output.put_line(SYSTIMESTAMP - strt); 



Код: plaintext
1.
+000000000 00:00:08.310970000

т.е. существенно медленнее - видать накладные расходы на обработку вызова подпрограммы
...
Рейтинг: 0 / 0
Обращение к полям элемента коллекции большого размера, напрямую или через копию элемента?
    #40049205
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
anvano
Получается, что без копирования быстрее,
Вывод неверный. Это всего лишь случайный шум от неидеальных условий.
Эксперименты надо повторять много раз:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
+000000000 00:00:04.654624000
+000000000 00:00:04.615528000

PL/SQL procedure successfully completed.

+000000000 00:00:04.461282000
+000000000 00:00:04.628789000

PL/SQL procedure successfully completed.

+000000000 00:00:04.649074000
+000000000 00:00:04.591293000

PL/SQL procedure successfully completed.

...
Рейтинг: 0 / 0
Обращение к полям элемента коллекции большого размера, напрямую или через копию элемента?
    #40049219
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2anvano,

с nocopy я намазал, зачеркнуть.

И вообще на другой вопрос отвечал:
на запись
Код: plsql
1.
2.
3.
t_row(i).field_1  := v_value_1;
...
t_row(i).field_k  := v_value_k;



поэлементное формирование стабильно быстрее, чем
Код: plsql
1.
2.
3.
4.
record_value.field_1  := v_value_1;
...
record_value.field_k  := v_value_k;
t_row(i) := record_value;



автоматически предположил это и для работы на чтение.
причин несимметричности не знаю, визуально, "лишняя запись" должна проявлять себя в обоих случаях.
В примере у тебя, кстати, не шибко широкий рекорд.
Широкий - это на сотню полей, хотя бы несколько десятков.

2Elic
ты прав, индюк напыщенный.
...
Рейтинг: 0 / 0
Обращение к полям элемента коллекции большого размера, напрямую или через копию элемента?
    #40049223
anvano
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Elic
anvano
Получается, что без копирования быстрее,
Вывод неверный. Это всего лишь случайный шум от неидеальных условий.
Эксперименты надо повторять много раз


Даже интересно с чего такой разброс.
Я очевидно не раз и не два эксперименты повторял, а оставил в цикле минут на 10
Причем на трёх разных физических машинах (серверах)

У меня результаты стабильно одинаковые.
...
Рейтинг: 0 / 0
Обращение к полям элемента коллекции большого размера, напрямую или через копию элемента?
    #40049561
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
anvano,

в циклах FOR i IN 1.. что-то посчитайте
напр sum_len=sum_len+length(tmp);

и после цикла напечатайте

...
stax
...
Рейтинг: 0 / 0
13 сообщений из 13, страница 1 из 1
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Обращение к полям элемента коллекции большого размера, напрямую или через копию элемента?
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]