RAC PL/SQL API

Часто у PL/SQL-разработчиков возникают вопросы при программировании в среде RAC. Ниже я попытаюсь на них ответить.

1) Как программно определить: выполняется ли мой PL/SQL-код в RAC-database или в Single Node ?

Ответ: для этого в пакете DBMS_UTILITY есть логическая функция IS_CLUSTER_DATABASE; она возвращает значение ИСТИНА, если выполнение происходит в БД запущенной в кластере.


Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - Production
With the Partitioning, Real Application Clusters, OLAP, Data Mining
and Real Application Testing options

SQL> begin
2 if dbms_utility.is_cluster_database then
3 dbms_output.put_line('I am in cluster');
4 end if;
5 end;
6 /
I am in cluster
2) Как программно определить узел, на котором в данный момент времени выполняется мой PL/SQL-код?
Ответ: Для этого можно применить функцию CURRENT_INSTANCE из того же пакета DBMS_UTILITY. Эта функция просто возвращает номер экземпляра БД, на котором работает ваша сессия.
SQL> exec dbms_output.put_line(dbms_utility.current_instance);
1
Есть второй способ: прочитать значение переменной INSTANCE из стандартного контекста сессии USERENV.
Ну а как прочитать это значение, вы прекрасно знаете - с помощью вызова SYS_CONTEXT('USERENV','INSTANCE')

3) Как программно определить список "живых" узлов кластера ?
Ответ: Для этого в замечательном пакете DBMS_UTILITY есть процедура ACTIVE_INSTANCES, которая через out-переменные возвращает список активных в данный момент узлов кластера.

SQL> begin
2 v_xTable dbms_utility.instance_table;
3 v_xCount pls_integer;
4 begin
5 dbms_utility.active_instances(v_xTable,
6 v_xCount);
7
8 for v_xIndex in 1..v_xCount
9 loop
10 dbms_output.put_line(v_xTable(v_xIndex).inst_number ||
11 ' => ' ||
12 v_xTable(v_xIndex).inst_name);
13 end loop;
14 end;
15 /
1 => rac1.us.oracle.com:racdb1
2 => rac2.us.oracle.com:racdb2
Обратите внимание, что в список попадут только "живые" узлы. Второй момент: имя узла возвращается в таком виде: полное имя хоста c именем экземпляра через символ двоеточия.

3) Если я включу в свои хранимые PL/SQL-процедуры RAC-specific код, то мне нужно каждый раз переключаться между двумя ветками кода через IF-оператор и вызовы IS_CLUSTER_DATABASE. Это замедлит быстродейстивие и приведет к раздуванию кода ! Если же я сделаю два варианта хранимой процедуры: один - для Single Node, второй - для RAC, то это означает что мне одновременно придется поддерживать две версии моего кода.
Есть какое-нибудь решение этой проблемы ?

Ответ: Решение есть, и очень элегантное. Для этого используется условная компиляция.
Сначала вы создаете символ условной компиляции в виде логической константы спецификации пакета:

create or replace package RAC_SERVICE is
Is_RAC_Database constant boolean := true;
end;


Затем через условную компиляцию вы оформляете куски кода специфичные для RAC:

create or replace procedure create_my_pipe
x number;
begin
$if RAC_SERVICE.Is_RAC_Database $then
x := rac_pipe.create_pipe('MY_PIPE');
$else
x:= dbms_pipe.create_pipe('MY_PIPE');
$end
end;

Преимущества:

  • не нужно сопровождать две версии исходного кода и устраняются проблемы связанные с этим;
  • переключение кода в Single Node производится простой заменой константы Is_RAC_Database в пакете RAC_SERVICE, с последующей его перекомпиляцией; "реинкарнацию" остального кода в Single Node - режим автоматически будет произведена самой СУБД;
  • в выполняемый код PVM (PL/SQL Virtual Machine) будут скомпилированы только те исходные тексты, которые специфичены для текущего режима работы (Single Instance или RAC).

2 комментария:

  1. а раздувание кода а последнем примере куда делось ? :)

    Michael

    ps. откройте обратно чат!
    pps. или, хотя бы - ответьте на почту

    ОтветитьУдалить
  2. Я имел в виду раздувание выполняемго кода, а не исходного текста - от этого никуда не деться.

    ОтветитьУдалить