Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Oracle Новый топик    Ответить
 Интересная ситуация при параллельном выполнении запроса  [new]
Romael
Member

Откуда: Москва
Сообщений: 194
Имеем следующий тестовый пример:
create or replace package pkg_TestDate is

  -- $CLEARCASE_USER: dtaranenko $
  -- $Date: 24.06.2009 17:21:07 $
  -- $CLEARCASE_ID_STR: \main\19 $
  -- Purpose : выгрузка данных в хранилище
  dvDate date;
  
  procedure SetReportDate(dpReportDate date);
    
  function  GetReportDate return date parallel_enable;
  
    
end pkg_TestDate;
/
create or replace package body pkg_TestDate is

  -- $CLEARCASE_USER: dtaranenko $
  -- $Date: 24.06.2009 17:21:07 $
  -- $CLEARCASE_ID_STR: \main\19 $
  -- Purpose : выгрузка данных в хранилище
    
  procedure SetReportDate(dpReportDate date)
  is
  begin
    dvDate := dpReportDate;
  end;
    
  function  GetReportDate return date parallel_enable
  is
  begin
    return dvDate;
  end;
     
end pkg_TestDate;
/

drop table TestData;

create table TestData  as
select level id
from dual
connect by level < 11;

begin
  pkg_TestDate.SetReportDate(to_date('31.05.2009', 'dd.mm.yyyy'));
end;
/
-- проверяем что дата установлена
select pkg_TestDate.GetReportDate 
from dual;

select pkg_TestDate.GetReportDate, t.id
from TestData t;
-- дата не пустая!!!

select --+ full(t) parallel(t 10)
  pkg_TestDate.GetReportDate, t.id
from TestData t;
-- Дата пустая!!!

Получается, что когда запрос выполняется в параллельных сессиях, функция не возвращает значение установленное в главной сессии.
Баг или фича?!
25 июн 09, 13:17    [7342550]     Ответить | Цитировать Сообщить модератору
 Re: Интересная ситуация при параллельном выполнении запроса  [new]
Человек и Кошка
Member

Откуда: настоящему индейцу завсегда везде ништяк (с)
Сообщений: 830
Romael
Баг или фича?!

фича.

PL/SQL User's Guide and Reference
Constants and variables are initialized every time a block or subprogram is entered. By default, variables are initialized to NULL. So, unless you expressly initialize a variable, its value is undefined.
Whether public or private, constants and variables declared in a package spec are initialized only once for each session.
25 июн 09, 13:28    [7342638]     Ответить | Цитировать Сообщить модератору
 Re: Интересная ситуация при параллельном выполнении запроса  [new]
Romael
Member

Откуда: Москва
Сообщений: 194
да нашёл уже.
прикольная фича. :)
25 июн 09, 14:24    [7343144]     Ответить | Цитировать Сообщить модератору
 Re: Интересная ситуация при параллельном выполнении запроса  [new]
Человек и Кошка
Member

Откуда: настоящему индейцу завсегда везде ништяк (с)
Сообщений: 830
Romael
прикольная

концептуальная
25 июн 09, 14:27    [7343164]     Ответить | Цитировать Сообщить модератору
 Re: Интересная ситуация при параллельном выполнении запроса  [new]
Romael
Member

Откуда: Москва
Сообщений: 194
PARALLEL_ENABLE

Declares that a stored function can be used safely in the slave sessions of parallel DML evaluations. The state of a main (logon) session is never shared with slave sessions. Each slave session has its own state, which is initialized when the session begins. The function result should not depend on the state of session (static) variables. Otherwise, results might vary across sessions. For information on the PARALLEL_ENABLE option, see the CREATE FUNCTION statement in the Oracle Database SQL Reference.
25 июн 09, 14:29    [7343172]     Ответить | Цитировать Сообщить модератору
 Re: Интересная ситуация при параллельном выполнении запроса  [new]
Romael
Member

Откуда: Москва
Сообщений: 194
Человек и Кошка
Romael
Баг или фича?!

фича.

PL/SQL User's Guide and Reference
Constants and variables are initialized every time a block or subprogram is entered. By default, variables are initialized to NULL. So, unless you expressly initialize a variable, its value is undefined.
Whether public or private, constants and variables declared in a package spec are initialized only once for each session.


это понятно, но это немного не то...
25 июн 09, 14:32    [7343197]     Ответить | Цитировать Сообщить модератору
 Re: Интересная ситуация при параллельном выполнении запроса  [new]
Timm
Member

Откуда: Moscow, Ё-burg
Сообщений: 3696
Romael
но это немного не то...

Именно то. Если хочешь чтобы инициализация пакетной переменной происходила в PX slaves, то надо добавить
pkg_TestDate.SetReportDate(to_date('31.05.2009', 'dd.mm.yyyy'));
в секцию инициализации пакета. Если parallel_min_servers=0, то вызов будет происходить при каждом старте PX slave, т.е. на каждый запрос с использованием параллелизма.
25 июн 09, 15:17    [7343582]     Ответить | Цитировать Сообщить модератору
 Re: Интересная ситуация при параллельном выполнении запроса  [new]
Romael
Member

Откуда: Москва
Сообщений: 194
[quot TimmИменно то. Если хочешь чтобы инициализация пакетной переменной происходила в PX slaves, то надо добавить
pkg_TestDate.SetReportDate(to_date('31.05.2009', 'dd.mm.yyyy'));
в секцию инициализации пакета. Если parallel_min_servers=0, то вызов будет происходить при каждом старте PX slave, т.е. на каждый запрос с использованием параллелизма.[/quot]

Весь смысл в том, что устанавливается дата-переменная!
Если бы это была константа, я бы не использовал переменный,
а вставил бы литерал прямо в селект.
25 июн 09, 15:57    [7343810]     Ответить | Цитировать Сообщить модератору
 Re: Интересная ситуация при параллельном выполнении запроса  [new]
suPPLer
Member

Откуда: Харків, Україна
Сообщений: 7794
Блог
Romael,

меняйте подход. Храните нужную дату (если уж надо хранить) в пользовательском контексте, а в процедуры/функции добавьте параметр для даты. И в запросах тогда передавайте в качестве параметра контекст...
25 июн 09, 17:42    [7344652]     Ответить | Цитировать Сообщить модератору
 Re: Интересная ситуация при параллельном выполнении запроса  [new]
Romael
Member

Откуда: Москва
Сообщений: 194
suPPLer
Romael,

меняйте подход. Храните нужную дату (если уж надо хранить) в пользовательском контексте, а в процедуры/функции добавьте параметр для даты. И в запросах тогда передавайте в качестве параметра контекст...


собственно, да! :)
25 июн 09, 17:54    [7344711]     Ответить | Цитировать Сообщить модератору
 Re: Интересная ситуация при параллельном выполнении запроса  [new]
Elic
Member

Откуда:
Сообщений: 29990
suPPLer
в пользовательском контексте
Ээээ... А поможет? Сессии-то разные...
25 июн 09, 17:56    [7344719]     Ответить | Цитировать Сообщить модератору
 Re: Интересная ситуация при параллельном выполнении запроса  [new]
suPPLer
Member

Откуда: Харків, Україна
Сообщений: 7794
Блог
Elic,

смотря как пользоваться...

0. Создаём контекст, если ещё нету.
1.
create or replace package pkg_TestDate is

  procedure SetReportDate(dpReportDate date);
    
  function  GetReportDate (p_date date) return date parallel_enable;
    
end pkg_TestDate;
/
create or replace package body pkg_TestDate is

  procedure SetReportDate(dpReportDate date)
  is
  begin
    dbms_session.set_context('OUR_CONTEXT', 'workdate', to_char(dpReportDate, 'dd.mm.yyyy'));
  end;
    
  function  GetReportDate (p_date date) return date parallel_enable
  is
  begin
    return p_Date;
  end;
     
end pkg_TestDate;
/

drop table TestData;

create table TestData  as
select level id
from dual
connect by level < 11;

begin
  pkg_TestDate.SetReportDate(to_date('31.05.2009', 'dd.mm.yyyy'));
end;
/

-- проверяем что дата установлена
select pkg_TestDate.GetReportDate(to_date(sys_context('OUR_CONTEXT', 'workdate'), 'dd.mm.yyyy'))
from dual;

select pkg_TestDate.GetReportDate(to_date(sys_context('OUR_CONTEXT', 'workdate'), 'dd.mm.yyyy')), t.id
from TestData t;
-- дата не пустая!!!

select --+ full(t) parallel(t 10)
  pkg_TestDate.GetReportDate(to_date(sys_context('OUR_CONTEXT', 'workdate'), 'dd.mm.yyyy')), t.id
from TestData t;

В итоге, дата хранится, пользоваться можем, литералы не пишем.

Или можно воспользоваться не пользовательским, а глобальным контекстом, который ACCESSED GLOBALLY, и напрямую без всяких параметров в функциях с ним работать... Но я подобного стараюсь избегать.
25 июн 09, 18:13    [7344804]     Ответить | Цитировать Сообщить модератору
 Re: Интересная ситуация при параллельном выполнении запроса  [new]
Elic
Member

Откуда:
Сообщений: 29990
suPPLer
select --+ full(t) parallel(t 10)
А как докажешь, что это работало парралельно?
25 июн 09, 18:23    [7344829]     Ответить | Цитировать Сообщить модератору
 Re: Интересная ситуация при параллельном выполнении запроса  [new]
Romael
Member

Откуда: Москва
Сообщений: 194
Elic
suPPLer
select --+ full(t) parallel(t 10)
А как докажешь, что это работало парралельно?


По сессиям видно (и плану)!

С контекстом все работает отлично и с локальным и с глобальным.
25 июн 09, 18:29    [7344842]     Ответить | Цитировать Сообщить модератору
 Re: Интересная ситуация при параллельном выполнении запроса  [new]
Romael
Member

Откуда: Москва
Сообщений: 194
а зачем в get передавать контекст?
у меня так работает с локальным контекстом:
procedure SetReportDate(dpReportDate date)
  is
  begin    
    dbms_session.set_context(sCTX_WH_DATEREPORT_Name, 'ReportDate', to_char(dpReportDate, 'DD.MM.YYYY'));
  end SetReportDate;
    
  function  GetReportDate return date parallel_enable
  is
    dvDate date;
  begin
    dvDate := to_date(SYS_CONTEXT(sCTX_WH_DATEREPORT_Name, 'ReportDate'), 'DD.MM.YYYY');
    return dvDate;
  end GetReportDate;
25 июн 09, 18:41    [7344876]     Ответить | Цитировать Сообщить модератору
 Re: Интересная ситуация при параллельном выполнении запроса  [new]
Romael
Member

Откуда: Москва
Сообщений: 194
Romael
Elic
suPPLer
select --+ full(t) parallel(t 10)
А как докажешь, что это работало парралельно?


По сессиям видно (и плану)!

С контекстом все работает отлично и с локальным и с глобальным.


прошу прощения, контекст в моем случае должен быть глобальным!

PS: я пересоздавал контекс с глобального на локальный (create or replace) и значение мое как то закэшировалось. Даже в совершенно другой сессии выдавал значение(мою дату).
25 июн 09, 18:52    [7344903]     Ответить | Цитировать Сообщить модератору
 Re: Интересная ситуация при параллельном выполнении запроса  [new]
Elic
Member

Откуда:
Сообщений: 29990
Romael
контекст в моем случае должен быть глобальным!
А что если два пользователя запустят отчёт параллельно? :)
25 июн 09, 19:17    [7344972]     Ответить | Цитировать Сообщить модератору
 Re: Интересная ситуация при параллельном выполнении запроса  [new]
suPPLer
Member

Откуда: Харків, Україна
Сообщений: 7794
Блог
Elic
А как докажешь, что это работало парралельно?


Дуалом клянусь, вах!

+
Connected to Oracle9i Enterprise Edition Release 9.2.0.6.0 
Connected as test
 
SQL> create or replace context test_context using pa_test;
 
Context created
 
SQL> create or replace package pa_test is
  2    procedure set_context(p_attr varchar2, p_val varchar2);
  3    procedure set_workdate(p_date date);
  4    function get_workdate(p_date date) return date;
  5  end;
  6  /
 
Package created
 
SQL> create or replace package body pa_test is
  2    procedure set_context(p_attr varchar2, p_val varchar2)
  3    is
  4    begin
  5      dbms_session.set_context('TEST_CONTEXT', p_attr, p_val);
  6    end;
  7  
  8    procedure set_workdate(p_date date)
  9    is
 10    begin
 11      set_context('workdate', to_char(p_date, 'dd.mm.yyyy'));
 12    end;
 13  
 14    function get_workdate(p_date date) return date
 15    is
 16    begin
 17      return p_date;
 18    end;
 19  end;
 20  /
 
Package body created
 
SQL> create table tmp parallel 4 as select level n from dual connect by level < 11;
 
Table created
 
SQL> exec pa_test.set_workdate(sysdate);
 
PL/SQL procedure successfully completed
 
SQL> set serverout on
SQL> exec dbms_output.put_line(pa_test.get_workdate(to_date(sys_context('test_context', 'workdate'), 'dd.mm.yyyy')));
 
25.06.09
 
PL/SQL procedure successfully completed
 
SQL> exec dbms_stats.gather_table_stats(user, 'TMP');
 
PL/SQL procedure successfully completed
 
SQL> select /*+ parallel(tmp 4) */
  2          n, pa_test.get_workdate(to_date(sys_context('test_context', 'workdate'), 'dd.mm.yyyy')) ddate from tmp;
 
         N DDATE
---------- -----------
         1 25.06.2009
         3 25.06.2009
         5 25.06.2009
         7 25.06.2009
         9 25.06.2009
         2 25.06.2009
         4 25.06.2009
         6 25.06.2009
         8 25.06.2009
        10 25.06.2009
 
10 rows selected
 
SQL> explain plan for
  2  select /*+ parallel(tmp 4) */
  3          n, pa_test.get_workdate(to_date(sys_context('test_context', 'workdate'), 'dd.mm.yyyy')) ddate from tmp;
 
Explained
 
SQL> select * from table(dbms_xplan.display('plan_table', null, 'ALL'));
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
| Id  | Operation            |  Name       | Rows  | Bytes | Cost  |  TQ    |IN-
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |             |    10 |    30 |     2 |        |
|   1 |  TABLE ACCESS FULL   | TMP         |    10 |    30 |     2 | 49,00  | P-
--------------------------------------------------------------------------------
 PX Slave SQL Information (identified by operation id): 
------------------------------------------------------
   1 - SELECT /*+ NO_EXPAND ROWID(A1) */ A1."N" FROM "TMP" PX_GRANULE(0, BLOCK_R
              A1
Note: cpu costing is off
 
16 rows selected

SQL> alter table tmp noparallel;
 
Table altered
 
SQL> explain plan for
  2  select
  3          n, pa_test.get_workdate(to_date(sys_context('test_context', 'workdate'), 'dd.mm.yyyy')) ddate from tmp;
 
Explained
 
SQL> select * from table(dbms_xplan.display('plan_table', null, 'ALL'));
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
--------------------------------------------------------------------
| Id  | Operation            |  Name       | Rows  | Bytes | Cost  |
--------------------------------------------------------------------
|   0 | SELECT STATEMENT     |             |    10 |    30 |     7 |
|   1 |  TABLE ACCESS FULL   | TMP         |    10 |    30 |     7 |
--------------------------------------------------------------------
Note: cpu costing is off
 
9 rows selected


Elic
А что если два пользователя запустят отчёт параллельно? :)


А вот тут и начнётся самое интересное, из-за чего всякие глобальные вещи я не люблю и не советую, если надобности в них нет...
25 июн 09, 20:54    [7345146]     Ответить | Цитировать Сообщить модератору
 Re: Интересная ситуация при параллельном выполнении запроса  [new]
Romael
Member

Откуда: Москва
Сообщений: 194
Elic
Romael
контекст в моем случае должен быть глобальным!
А что если два пользователя запустят отчёт параллельно? :)


будет каша :)

это не совсем отчет, запскается не юзером, а системой.

здесь привел просто тестовый пример, показывающий ситуацию, что функция с parallel_enable
должна быть безопасной для || выполнения.

Просто интересно, что переменная используемая в || селекте распространяется на все дочерние сессии, а если использовать функцию возвращающую пакетную переменную установленную выше то фиг.

declare
 i number := 123;
begin
  select --+ full(a)  parallel(a 10)
  from a
  where a.id = i;
end;
/
-----------------------------------
setfNumber(123);
...
begin
  select --+ full(a)  parallel(a 10)
  from a
  where a.id = fgetNumber; -- функция возвращающая пакетную переменную
end;
/
26 июн 09, 10:25    [7346384]     Ответить | Цитировать Сообщить модератору
 Re: Интересная ситуация при параллельном выполнении запроса  [new]
Человек и Кошка
Member

Откуда: настоящему индейцу завсегда везде ништяк (с)
Сообщений: 830
Romael,

SQL> select --+ full(t) parallel(t 10)
  2    pkg_TestDate.GetReportDate, t.id
  3  from TestData t;
 
GETREPORTDATE         ID
------------- ----------
                       1
                       2
                       3
                       4
                       5
                       6
                       7
                       8
                       9
                      10
 
10 rows selected

SQL> with a as(select /*+ materialize */ pkg_TestDate.GetReportDate d from dual)
  2  select --+ full(t) parallel(t 10)
  3    d, t.id
  4  from TestData t, a;
 
D                   ID
----------- ----------
31.05.2009           1
31.05.2009           2
31.05.2009           3
31.05.2009           4
31.05.2009           5
31.05.2009           6
31.05.2009           7
31.05.2009           8
31.05.2009           9
31.05.2009          10
 
10 rows selected

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 3185700349

---------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                  | Name                        | Rows  | Bytes | Cost (%CPU)| Time     |    TQ  |IN-OUT| PQ Distrib |
---------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |                             |    10 |   220 |     7   (0)| 00:00:01 |        |      |            |
|   1 |  TEMP TABLE TRANSFORMATION |                             |       |       |            |          |        |      |            |
|   2 |   LOAD AS SELECT           |                             |       |       |            |          |        |      |            |
|   3 |    FAST DUAL               |                             |     1 |       |     2   (0)| 00:00:01 |        |      |            |
|   4 |   PX COORDINATOR           |                             |       |       |            |          |        |      |            |
|   5 |    PX SEND QC (RANDOM)     | :TQ10001                    |    10 |   220 |     5   (0)| 00:00:01 |  Q1,01 | P->S | QC (RAND)  |
|   6 |     MERGE JOIN CARTESIAN   |                             |    10 |   220 |     5   (0)| 00:00:01 |  Q1,01 | PCWP |            |
|   7 |      BUFFER SORT           |                             |       |       |            |          |  Q1,01 | PCWC |            |
|   8 |       PX RECEIVE           |                             |     1 |     9 |     2   (0)| 00:00:01 |  Q1,01 | PCWP |            |
|   9 |        PX SEND BROADCAST   | :TQ10000                    |     1 |     9 |     2   (0)| 00:00:01 |        | S->P | BROADCAST  |
|  10 |         VIEW               |                             |     1 |     9 |     2   (0)| 00:00:01 |        |      |            |
|  11 |          TABLE ACCESS FULL | SYS_TEMP_0FD9D6662_64439D3D |     1 |     9 |     2   (0)| 00:00:01 |        |      |            |
|  12 |      BUFFER SORT           |                             |    10 |   130 |     5   (0)| 00:00:01 |  Q1,01 | PCWP |            |
|  13 |       PX BLOCK ITERATOR    |                             |    10 |   130 |     2   (0)| 00:00:01 |  Q1,01 | PCWC |            |
|  14 |        TABLE ACCESS FULL   | TESTDATA                    |    10 |   130 |     2   (0)| 00:00:01 |  Q1,01 | PCWP |            |
---------------------------------------------------------------------------------------------------------------------------------------
26 июн 09, 10:54    [7346560]     Ответить | Цитировать Сообщить модератору
Все форумы / Oracle Ответить