powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Oracle [игнор отключен] [закрыт для гостей] / многократный вызов функции
8 сообщений из 8, страница 1 из 1
многократный вызов функции
    #38879870
shtirlitz56
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Всем привет! Не могу понять, зачем при выборе данных из вложенного запроса оракл пересчитывает функцию... Тот же самый запрос на PostgreSQL по приколу написал - там лишь 1 раз функция вызывается. Вот сам запрос:
Код: 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.
select * from --зачем 2-й раз оракл обращается к функции? (справедливо лишь в случае истинности условия в 5-й строке запроса)
( 
select  hz a0 from dual --1-й раз оракл обрашается к функции
)
where  a0 = 1 

--исходники функции и сиквенса который считает кол-во запусков:

CREATE SEQUENCE s1
START WITH 0
INCREMENT BY 1
MINVALUE 0
NOCACHE 
NOCYCLE 
NOORDER 
NOKEEP
GLOBAL;

/

CREATE OR REPLACE FUNCTION hz RETURN varchar2 IS
t number;
BEGIN
   select S1.nextval into t from dual;
   DBMS_OUTPUT.PUT_LINE('seq='||t||' time='||to_char(sysdate,'HH24:MI:SS'));
   RETURN 1 ;
END hz;



p.s. Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
...
Рейтинг: 0 / 0
многократный вызов функции
    #38879875
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
shtirlitz56зачем при выборе данных из вложенного запроса оракл пересчитывает функцию...Потому что нигде не обещал обратного. Считай, что совершенно в разны кусках SQL-движка нужно сперва проверить условие, а потом сформировать актуальные значения select-list-а.
Никогда не следует закладываться на количество вызовов.

shtirlitz56Тот же самый запрос на PostgreSQLработает неправильно, не так ли?
...
Рейтинг: 0 / 0
многократный вызов функции
    #38879877
shtirlitz56
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Elic,

ХЗ вроде честно постгрес отработал, но и с такой функцией то грех конечно неправильный ответ дать :)
...
Рейтинг: 0 / 0
многократный вызов функции
    #38879906
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
shtirlitz56,

Твой случай:
http://orasql.org/2013/06/10/too-many-function-executions/
И объявляй функции deterministic - кеширование поможет снизить количество вызовов
...
Рейтинг: 0 / 0
многократный вызов функции
    #38879988
shtirlitz56
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
xtender,

Спасибо! Интересная статья! Почерпнул из неё пару способов избавиться от многократного вызова функции. 1-й способ (не требует переписывания запроса и функции):
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
 begin
    dbms_sqltune.import_sql_profile(
       sql_text    => 'select * from ( select hz a0 from dual ) where  a0 = 1'
       ,profile     => sys.sqlprof_attr(
                               q'[NO_MERGE(@SEL$2)]'
                              ,q'[OPT_PARAM('_OPTIMIZER_FILTER_PUSHDOWN' 'FALSE')]'
                            )
      ,category    => 'DEFAULT'
       ,name        => 'TEST_PROFILE'
     ,force_match => true
      ,replace     => true
     );
   end;
  /



2й способ (просто добавляем в селект rownum, и deterministic в объявление функции) :
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
begin
dbms_sqltune.drop_sql_profile('TEST_PROFILE');
end;
/
CREATE OR REPLACE FUNCTION hz RETURN varchar2 deterministic  IS
t number;
BEGIN
   select S1.nextval into t from dual;
   DBMS_OUTPUT.PUT_LINE('seq='||t||' time='||to_char(sysdate,'HH24:MI:SS'));
   RETURN '1' ;
END hz;
/
select * from ( select rownum,hz a0 from dual ) where  a0 = 1 
...
Рейтинг: 0 / 0
многократный вызов функции
    #38880138
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
shtirlitz561-й способ

Код: 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.
SQL> connect scott@pdb1sol12
Enter password: *****
Connected.
SQL> select  banner
  2    from  v$version
  3  /

BANNER
--------------------------------------------------------------------------------
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
PL/SQL Release 12.1.0.2.0 - Production
CORE    12.1.0.2.0      Production
TNS for 64-bit Windows: Version 12.1.0.2.0 - Production
NLSRTL Version 12.1.0.2.0 - Production

SQL> CREATE SEQUENCE s1
  2  START WITH 0
  3  INCREMENT BY 1
  4  MINVALUE 0
  5  NOCACHE 
  6  NOCYCLE 
  7  NOORDER 
  8  NOKEEP
  9  GLOBAL;

Sequence created.

SQL> CREATE OR REPLACE FUNCTION hz RETURN varchar2 IS
  2  t number;
  3  BEGIN
  4     select S1.nextval into t from dual;
  5     DBMS_OUTPUT.PUT_LINE('seq='||t||' time='||to_char(sysdate,'HH24:MI:SS'));
  6     RETURN 1 ;
  7  END hz;
  8  /

Function created.

SQL> begin
  2      dbms_sqltune.import_sql_profile(
  3         sql_text    => 'select * from ( select hz a0 from dual ) where  a0 = 1'
  4         ,profile     => sys.sqlprof_attr(
  5                                 q'[NO_MERGE(@SEL$2)]'
  6                                ,q'[OPT_PARAM('_OPTIMIZER_FILTER_PUSHDOWN' 'FALSE')]'
  7                              )
  8        ,category    => 'DEFAULT'
  9         ,name        => 'TEST_PROFILE'
 10       ,force_match => true
 11        ,replace     => true
 12       );
 13     end;
 14  /

PL/SQL procedure successfully completed.

SQL> set autotrace on
SQL> select * from ( select hz a0 from dual ) where  a0 = 1
  2  /

A0
--------------------------------------------------------------------------------
1

seq=1 time=06:34:39
seq=2 time=06:34:39
seq=3 time=06:34:39

Execution Plan
----------------------------------------------------------
Plan hash value: 885813501

-------------------------------------------------------------------------
| Id  | Operation        | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------
|   0 | SELECT STATEMENT |      |     1 |  2002 |     2   (0)| 00:00:01 |
|*  1 |  VIEW            |      |     1 |  2002 |     2   (0)| 00:00:01 |
|   2 |   FAST DUAL      |      |     1 |       |     2   (0)| 00:00:01 |
-------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(TO_NUMBER("A0")=1)

Note
-----
   - SQL profile "TEST_PROFILE" used for this statement


Statistics
----------------------------------------------------------
          6  recursive calls
          9  db block gets
          3  consistent gets
          0  physical reads
       2084  redo size
        508  bytes sent via SQL*Net to client
        483  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

SQL> 



Deterministic тоже не дает гарантиии. Ну и DUAL с его оптимизациями в последних версиях дeлает все это as clear as mud. Посему нужен реальный join и stopkey чтобы предотвратить push_pred. Но это ещё не все:

Код: 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.
SQL> create table tbl as select * from dual;

Table created.

SQL> select a0 from tbl,(select hz a0 from dual where rownum = 1) v where a0 = 1;

A0
--------------------------------------------------------------------------------
1

seq=101 time=07:20:52

Execution Plan
----------------------------------------------------------
Plan hash value: 1139523803

-----------------------------------------------------------------------------
| Id  | Operation            | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |      |     1 |  2002 |     5   (0)| 00:00:01 |
|   1 |  MERGE JOIN CARTESIAN|      |     1 |  2002 |     5   (0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL  | TBL  |     1 |       |     3   (0)| 00:00:01 |
|   3 |   BUFFER SORT        |      |     1 |  2002 |     2   (0)| 00:00:01 |
|*  4 |    VIEW              |      |     1 |  2002 |     2   (0)| 00:00:01 |
|*  5 |     COUNT STOPKEY    |      |       |       |            |          |
|   6 |      FAST DUAL       |      |     1 |       |     2   (0)| 00:00:01 |
-----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - filter(TO_NUMBER("A0")=1)
   5 - filter(ROWNUM=1)


Statistics
----------------------------------------------------------
          2  recursive calls
          3  db block gets
          4  consistent gets
          0  physical reads
        732  redo size
        508  bytes sent via SQL*Net to client
        483  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
          1  rows processed

SQL> select a0 from (select hz a0 from dual where rownum = 1) v,tbl where a0 = 1;

A0
--------------------------------------------------------------------------------
1

seq=102 time=07:21:17
seq=103 time=07:21:17
seq=104 time=07:21:17

Execution Plan
----------------------------------------------------------
Plan hash value: 3991261284

-----------------------------------------------------------------------------
| Id  | Operation            | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |      |     1 |  2002 |     5   (0)| 00:00:01 |
|   1 |  MERGE JOIN CARTESIAN|      |     1 |  2002 |     5   (0)| 00:00:01 |
|*  2 |   VIEW               |      |     1 |  2002 |     2   (0)| 00:00:01 |
|*  3 |    COUNT STOPKEY     |      |       |       |            |          |
|   4 |     FAST DUAL        |      |     1 |       |     2   (0)| 00:00:01 |
|   5 |   TABLE ACCESS FULL  | TBL  |     1 |       |     3   (0)| 00:00:01 |
-----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter(TO_NUMBER("A0")=1)
   3 - filter(ROWNUM=1)


Statistics
----------------------------------------------------------
          6  recursive calls
          9  db block gets
          6  consistent gets
          0  physical reads
       2092  redo size
        508  bytes sent via SQL*Net to client
        483  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

SQL> 



Т.е. число выполнений функции зависит от порядка MERGE. Значит понадобится хинт LEADING:

Код: 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.
SQL> select /*+ leading(tbl v) */ a0 from tbl,(select hz a0 from dual where rownum = 1) v where a0 = 1;

A0
--------------------------------------------------------------------------------
1

seq=105 time=07:24:10

Execution Plan
----------------------------------------------------------
Plan hash value: 1139523803

-----------------------------------------------------------------------------
| Id  | Operation            | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |      |     1 |  2002 |     5   (0)| 00:00:01 |
|   1 |  MERGE JOIN CARTESIAN|      |     1 |  2002 |     5   (0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL  | TBL  |     1 |       |     3   (0)| 00:00:01 |
|   3 |   BUFFER SORT        |      |     1 |  2002 |     2   (0)| 00:00:01 |
|*  4 |    VIEW              |      |     1 |  2002 |     2   (0)| 00:00:01 |
|*  5 |     COUNT STOPKEY    |      |       |       |            |          |
|   6 |      FAST DUAL       |      |     1 |       |     2   (0)| 00:00:01 |
-----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - filter(TO_NUMBER("A0")=1)
   5 - filter(ROWNUM=1)


Statistics
----------------------------------------------------------
          3  recursive calls
          3  db block gets
          4  consistent gets
          0  physical reads
        732  redo size
        508  bytes sent via SQL*Net to client
        483  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
          1  rows processed

SQL> select /*+ leading(tbl v) */ a0 from (select hz a0 from dual where rownum = 1) v,tbl where a0 = 1;

A0
--------------------------------------------------------------------------------
1

seq=106 time=07:24:35

Execution Plan
----------------------------------------------------------
Plan hash value: 1139523803

-----------------------------------------------------------------------------
| Id  | Operation            | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |      |     1 |  2002 |     5   (0)| 00:00:01 |
|   1 |  MERGE JOIN CARTESIAN|      |     1 |  2002 |     5   (0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL  | TBL  |     1 |       |     3   (0)| 00:00:01 |
|   3 |   BUFFER SORT        |      |     1 |  2002 |     2   (0)| 00:00:01 |
|*  4 |    VIEW              |      |     1 |  2002 |     2   (0)| 00:00:01 |
|*  5 |     COUNT STOPKEY    |      |       |       |            |          |
|   6 |      FAST DUAL       |      |     1 |       |     2   (0)| 00:00:01 |
-----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - filter(TO_NUMBER("A0")=1)
   5 - filter(ROWNUM=1)


Statistics
----------------------------------------------------------
          3  recursive calls
          3  db block gets
          4  consistent gets
          0  physical reads
        688  redo size
        508  bytes sent via SQL*Net to client
        483  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
          1  rows processed

SQL> 



SY.
...
Рейтинг: 0 / 0
многократный вызов функции
    #38880230
shtirlitz56
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SY,

вроде бы все понятно, но по 1-му способу у меня план выполнения такой же, однако же функция лишь 1 раз каждый раз вызывается:
Код: 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.
select * from ( select hz a0 from dual )where  a0 = 1 


Plan hash value: 885813501
 
-------------------------------------------------------------------------
| Id  | Operation        | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------
|   0 | SELECT STATEMENT |      |     1 |  2002 |     2   (0)| 00:00:01 |
|*  1 |  VIEW            |      |     1 |  2002 |     2   (0)| 00:00:01 |
|   2 |   FAST DUAL      |      |     1 |       |     2   (0)| 00:00:01 |
-------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   1 - filter(TO_NUMBER("A0")=1)
 
Note
-----
   - SQL profile "TEST_PROFILE" used for this statement


buffer is not pinned count	1
buffer is pinned count	1
bytes received via SQL*Net from client	1473
bytes sent via SQL*Net to client	6451
calls to get snapshot scn: kcmgss	5
calls to kcmgas	1
calls to kcmgcs	3
commit cleanouts	1
commit cleanouts successfully completed	1
consistent gets	1
consistent gets examination	1
consistent gets examination (fastpath)	1
consistent gets from cache	1
db block changes	4
db block gets	3
db block gets from cache	3
deferred (CURRENT) block cleanout applications	1
enqueue releases	2
enqueue requests	2
execute count	4
HSC Heap Segment Block Changes	1
index fetch by key	1
logical read bytes from cache	32768
messages sent	1
non-idle wait count	9
opened cursors cumulative	5
opened cursors current	1
parse count (total)	3
recursive calls	2
redo entries	2
redo size	716
redo synch time (usec)	1399
redo synch time overhead (usec)	48
redo synch time overhead count (  2ms)	1
redo synch writes	1
redo write info find	1
Requests to/from client	4
session cursor cache count	-1
session cursor cache hits	5
session logical reads	4
sorts (memory)	1
sorts (rows)	157
SQL*Net roundtrips to/from client	4
undo change vector size	216
user calls	6
workarea executions - optimal	3


seq=149 time=23:00:22
seq=150 time=23:00:52
seq=151 time=23:01:14
seq=152 time=23:01:56
...
Рейтинг: 0 / 0
многократный вызов функции
    #38880243
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
SY
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
SQL> select * from ( select hz a0 from dual ) where  a0 = 1
  2  /

A0
--------------------------------------------------------------------------------
1

seq=1 time=06:34:39
seq=2 time=06:34:39
seq=3 time=06:34:39


Это характерное поведение SQL*Plus. если вызвать в другом клиенте или обернуть в
Код: plsql
1.
2.
3.
4.
begin
  for r in (select * from ( select hz a0 from dual ) where  a0 = 1) loop null; end loop;
end;
/

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


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