powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Функция TREAT - накладные расходы от частого использования?
6 сообщений из 6, страница 1 из 1
Функция TREAT - накладные расходы от частого использования?
    #39339323
rpovarov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Использую PIPELINED функцию в комбинации с PARALLEL_ENABLE для генерирования тестовых данных. На вход подаётся одна таблица со списком "шаблонов", на выходе генерируются логически связанные между собой данные для нескольких таблиц. Данные выходят в виде объектов, которые раскладываются по таблицам с помощью multitable insert. Такой INSERT выглядит примерно так (образец):
Код: 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.
INSERT 
/*+ PARALLEL APPEND */ 
FIRST
WHEN r is of type(TEST_NODE_OT)
THEN
  INTO TEST_NODE
  VALUES (
     treat(r as TEST_NODE_OT).NODE_ID
    ,treat(r as TEST_NODE_OT).NODE_NAME
    ,treat(r as TEST_NODE_OT).TEST_SID
 )
WHEN r is of type(TEST_ITEM_OT)
THEN
  INTO TEST_ITEM
  VALUES (
     treat(r as TEST_ITEM_OT).ITEM_ID
    ,treat(r as TEST_ITEM_OT).ITEM_TYPE
    ,treat(r as TEST_ITEM_OT).ITEM_NAME
    ,treat(r as TEST_ITEM_OT).NODE_ID
    ,treat(r as TEST_ITEM_OT).PARENT_ID
    ,treat(r as TEST_ITEM_OT).TEST_SID
 )
select 
  VALUE(nt) as r
from  TABLE(test_pipeline.f_test(CURSOR(SELECT * FROM test_input))) nt
;


("боевой" insert содержит с десяток таблиц по полтора десятка полей, выглядит страшно, но генерируется автоматически)

Получается очень удобно, потому что сложная иерархическая логика распределена между объектами (в конструкторе и методах) и самой PIPELINED функцией, выглядит наглядно, изменения и добавления новых элементов и связей не тащат за собой перечитывание (как но работает??) и перекапывание кода. При выполнении иерархическая структура (клиент, его тарифы, его службы, атрибуты, и т.п.) генерируются в одном потоке, на диск пишутся тоже рядом друг с другом. Работает вроде достаточно шустро. Одним словом, отказываться от такой удобной штуки очень не хочется.

Но не даёт покоя куча вызовов TREAT. Перерыл документацию и форумы, но так и не нашёл, насколько такая конструкция утяжеляет запрос (если вообще утяжеляет). Может, кто-то уже с этим сталкивался? Стоит ли ломать голову поисками оптимизаций в этом месте?

Заранее спасибо!

Код для теста:

Код: 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.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
/*
DROP TABLE "TEST_INPUT";
DROP TABLE "TEST_ITEM";
DROP TABLE "TEST_NODE";
DROP SEQUENCE "TEST_ITEM_SEQ";
DROP SEQUENCE "TEST_NODE_SEQ";
DROP PACKAGE "TEST_PIPELINE";
DROP PACKAGE BODY "TEST_PIPELINE";
DROP TYPE "TEST_NODE_OT";
DROP TYPE "TEST_ITEM_OT";
DROP TYPE "TEST_NTT";
DROP TYPE "TEST_OT";
--*/

--------------------------------------------------------
--  DDL for Type TEST_OT
--------------------------------------------------------

  CREATE OR REPLACE EDITIONABLE TYPE "TEST_OT" FORCE AS OBJECT  
( 
  TEST_SID VARCHAR2(50 CHAR)
) NOT FINAL;

/
--------------------------------------------------------
--  DDL for Type TEST_NTT
--------------------------------------------------------

  CREATE OR REPLACE EDITIONABLE TYPE "TEST_NTT" AS TABLE OF TEST_OT;

/
--------------------------------------------------------
--  DDL for Type TEST_NODE_OT
--------------------------------------------------------

  CREATE OR REPLACE EDITIONABLE TYPE "TEST_NODE_OT" UNDER TEST_OT
( 
  NODE_ID    NUMBER,
	NODE_NAME  VARCHAR2(50 CHAR), 
  CONSTRUCTOR FUNCTION TEST_NODE_OT (p_node_id number, p_node_type varchar2) RETURN SELF AS RESULT
) FINAL;
/
CREATE OR REPLACE EDITIONABLE TYPE BODY "TEST_NODE_OT" AS
  CONSTRUCTOR FUNCTION TEST_NODE_OT(p_node_id number, p_node_type varchar2)
       RETURN SELF AS RESULT IS
        l_sid number;
     BEGIN
        l_sid := sys_context('USERENV', 'SID');
    
        NODE_ID         :=  p_node_id;
        NODE_NAME       :=  'Node: '||p_node_type;
        TEST_SID        :=  'thread: '||l_sid;

        RETURN;
     END;
END;

/
--------------------------------------------------------
--  DDL for Type TEST_ITEM_OT
--------------------------------------------------------

  CREATE OR REPLACE EDITIONABLE TYPE "TEST_ITEM_OT" UNDER TEST_OT
( 
  ITEM_ID    NUMBER,
  ITEM_TYPE  VARCHAR2(50),
	ITEM_NAME  VARCHAR2(50 CHAR), 
  NODE_ID    NUMBER,
  PARENT_ID  NUMBER,
  CONSTRUCTOR FUNCTION TEST_ITEM_OT (p_item_id number, p_item_type varchar2, p_node_id number, p_parent_id number) RETURN SELF AS RESULT
) FINAL;
/
CREATE OR REPLACE EDITIONABLE TYPE BODY "TEST_ITEM_OT" AS
  CONSTRUCTOR FUNCTION TEST_ITEM_OT(p_item_id number, p_item_type varchar2, p_node_id number, p_parent_id number)
       RETURN SELF AS RESULT IS
        l_sid number;
     BEGIN
        l_sid := sys_context('USERENV', 'SID');
    
        ITEM_ID     :=  p_item_id;
        ITEM_TYPE   :=  p_item_type;
        ITEM_NAME   :=  p_item_type||'_'||to_char(ITEM_ID);
        NODE_ID     :=  p_node_id;
        PARENT_ID   :=  p_parent_id;  
        TEST_SID    :=  'thread: '||l_sid;

        RETURN;
     END;
END;

/
--------------------------------------------------------
--  DDL for Sequence TEST_ITEM_SEQ
--------------------------------------------------------

   CREATE SEQUENCE  "TEST_ITEM_SEQ"  MINVALUE 1 MAXVALUE 99999999999999 INCREMENT BY 1 START WITH 35529301 CACHE 100 NOORDER  NOCYCLE  NOPARTITION ;
--------------------------------------------------------
--  DDL for Sequence TEST_NODE_SEQ
--------------------------------------------------------

   CREATE SEQUENCE  "TEST_NODE_SEQ"  MINVALUE 1 MAXVALUE 99999999999999 INCREMENT BY 1 START WITH 1362601 CACHE 100 NOORDER  NOCYCLE  NOPARTITION ;
--------------------------------------------------------
--  DDL for Table TEST_INPUT
--------------------------------------------------------

  CREATE TABLE "TEST_INPUT" 
   (	"NODE_TYPE" VARCHAR2(50 CHAR), 
	"ITEM_TYPE" VARCHAR2(50 CHAR), 
	"ITEM_COUNT" NUMBER
   ) ;
--------------------------------------------------------
--  DDL for Table TEST_ITEM
--------------------------------------------------------

  CREATE TABLE "TEST_ITEM" 
   (	"ITEM_ID" NUMBER, 
	"ITEM_TYPE" VARCHAR2(50), 
	"ITEM_NAME" VARCHAR2(50 CHAR), 
	"NODE_ID" NUMBER, 
	"PARENT_ID" NUMBER, 
	"TEST_SID" VARCHAR2(50 CHAR)
   ) ;
--------------------------------------------------------
--  DDL for Table TEST_NODE
--------------------------------------------------------

  CREATE TABLE "TEST_NODE" 
   (	"NODE_ID" NUMBER, 
	"NODE_NAME" VARCHAR2(50 CHAR), 
	"TEST_SID" VARCHAR2(50 CHAR)
   ) ;
--------------------------------------------------------
--  DDL for Package TEST_PIPELINE
--------------------------------------------------------

  CREATE OR REPLACE EDITIONABLE PACKAGE "TEST_PIPELINE" AS 

TYPE t_test_input IS REF CURSOR RETURN TEST_INPUT%rowtype;

FUNCTION f_test (p_cursor IN t_test_input, p_limit_size IN PLS_INTEGER DEFAULT 1000)
  RETURN test_ntt PIPELINED
  CLUSTER p_cursor BY (node_type) 
  PARALLEL_ENABLE  
    (PARTITION p_cursor BY HASH(node_type))
--    (PARTITION p_cursor BY ANY);
  ;
END TEST_PIPELINE;

/
--------------------------------------------------------
--  DDL for Package Body TEST_PIPELINE
--------------------------------------------------------

  CREATE OR REPLACE EDITIONABLE PACKAGE BODY "TEST_PIPELINE" AS 


FUNCTION f_test (p_cursor IN t_test_input, p_limit_size IN PLS_INTEGER DEFAULT 1000)
  RETURN test_ntt PIPELINED
  CLUSTER p_cursor BY (node_type) 
  PARALLEL_ENABLE  
    (PARTITION p_cursor BY HASH(node_type))
--    (PARTITION p_cursor BY ANY)
  IS
  TYPE cursor_ntt IS TABLE OF TEST_INPUT%rowtype;
  nt_src_data cursor_ntt;
  l_node_id  NUMBER;
  l_item_id  NUMBER;
BEGIN
  LOOP
    FETCH p_cursor BULK COLLECT INTO nt_src_data LIMIT p_limit_size;
    EXIT WHEN nt_src_data.COUNT = 0;
    
    FOR i IN 1 .. nt_src_data.COUNT LOOP

      -- generate TEST_NODE row    
      l_node_id    :=  test_node_seq.NEXTVAL;
      PIPE ROW (TEST_NODE_OT (
                  p_node_id    =>    l_node_id, 
                  p_node_type  =>    nt_src_data(i).node_type
                ));
      
      FOR k in 1..nt_src_data(i).item_count LOOP
      
        -- generate TEST_ITEM row
        l_item_id    :=  test_item_seq.NEXTVAL;
        PIPE ROW (TEST_ITEM_OT (
                   p_item_id    =>  l_item_id,
                   p_item_type  =>  nt_src_data(i).item_type,
                   p_node_id    =>  l_node_id,
                   p_parent_id  =>  null
                  ));
        
        IF nt_src_data(i).item_type = 'item_item' THEN          
          PIPE ROW (TEST_ITEM_OT (
                     p_item_id    =>  test_item_seq.NEXTVAL,
                     p_item_type  =>  nt_src_data(i).item_type,
                     p_node_id    =>  l_node_id,
                     p_parent_id  =>  l_item_id
                    ));
        END IF;
        
      END LOOP; -- item_count
      
    END LOOP;  -- nt_src_data

  END LOOP; -- p_cursor
  
  CLOSE p_cursor;
  RETURN;
  
EXCEPTION
  WHEN NO_DATA_NEEDED THEN
    RETURN;
  WHEN OTHERS THEN
--    logEvent(l_module_name||'_FAILED', substr(dbms_utility.format_error_stack || ' >> ' || dbms_utility.format_error_backtrace, 1, 3000));
    raise;   
END f_test;

END TEST_PIPELINE;

/




Входные данные для insert'a
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
-- generate sample data
INSERT /*+ PARALLEL(4) ENABLE_PARALLEL_DML */ ALL 
INTO test_input (node_type, item_type, item_count) VALUES ('node_'||test_id, 'item1', 100 )
INTO test_input (node_type, item_type, item_count) VALUES ('node_'||test_id, 'item2', 200 )
INTO test_input (node_type, item_type, item_count) VALUES ('node_'||test_id, 'item_item', 10 )
WITH p AS (SELECT ROWNUM as test_id FROM DUAL CONNECT BY LEVEL <= 100)
SELECT * FROM p
;

...
Рейтинг: 0 / 0
Функция TREAT - накладные расходы от частого использования?
    #39459594
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rpovarovНо не даёт покоя куча вызовов TREAT.Не вникал в смысл наследования, но даже при его наличии в чем проблема сделать коллекцию интересующего типа чтоб не делать treat?

А вообще, при использовании функций, возвращающих коллекции с большим числом элементов, волновать должно даже не это, а то что конструктор вызывается для каждой строки.
И вот на это могут уходить заметные накладные расходы CPU.
Никотин делал неплохой тест на эту тему 12044200 .
...
Рейтинг: 0 / 0
Функция TREAT - накладные расходы от частого использования?
    #39459808
rpovarov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
dbms_photoshopв чем проблема сделать коллекцию интересующего типа чтоб не делать treat?


Вся идея была в том, что из pipelined функции потоком выходят разные форматы, которые потом раскладываются по соответствующим таблицам мульти-инсертом. И без treat не достать полей записи.

А конструкторы да - жрут :( Но без объектов не получается такая красивая мультиформатная заморочка...
...
Рейтинг: 0 / 0
Функция TREAT - накладные расходы от частого использования?
    #39459810
rpovarov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Точнее, для такого мультинсерта нужны объекты. А treat - уже последствия вынужденной работы с объектами.
...
Рейтинг: 0 / 0
Функция TREAT - накладные расходы от частого использования?
    #39459962
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rpovarov,

Я так понимаю что данные в таблицах хранялся реляционно и число атрубитов каждой строки на выходе pipelined фиксировано.
Ну так сделай флажок указывающий в какую таблицу записывать и НЕ используй "is of type", "treat" и наследование.
...
Рейтинг: 0 / 0
Функция TREAT - накладные расходы от частого использования?
    #39459972
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rpovarov,

Необходимость в pipelined тоже весьма сомнительна.
Все можно сделать одним запросом.
...
Рейтинг: 0 / 0
6 сообщений из 6, страница 1 из 1
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Функция TREAT - накладные расходы от частого использования?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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