Oracle
 sql >> база данни >  >> RDS >> Oracle

начини за избягване на глобални временни таблици в oracle

Нека първо отговорим на втория въпрос:

"защо да се махнем от GTT? наистина ли са толкова лоши."

Преди няколко дни събирах доказателство за концепция, което зарежда голям XML файл (~18MB) в XMLType. Тъй като не исках да съхранявам XMLType постоянно, се опитах да го заредя в PL/SQL променлива (памет на сесията) и временна таблица. Зареждането му във временна таблица отне пет пъти повече време от зареждането му в променлива XMLType (5 секунди в сравнение с 1 секунда). Разликата е, че временните таблици не са структури на паметта:те се записват на диск (по-специално номинираното от вас временно пространство за таблици).

Ако искате да кеширате много данни, съхраняването им в паметта ще натовари PGA, което не е добре, ако имате много сесии. Така че това е компромис между RAM и времето.

Към първия въпрос:

„Може ли някой да покаже как да трансформира горните примерни заявки в колекции и/или курсори?“

Заявките, които публикувате, могат да бъдат обединени в едно изявление:

SELECT case when a.column_a IS NULL OR a.column_a = ' ' 
           then b.data_a
           else  column_a end AS someA,
       a.someB,
       a.someC
FROM TABLE_A a
      left outer join TABLE_B b
          on ( a.column_b = b.data_b AND a.column_c = 'C' )
WHERE condition_1 = 'YN756'
  AND type_cd = 'P'
  AND TO_NUMBER(TO_CHAR(m_date, 'MM')) = '12'
  AND (lname LIKE (v_LnameUpper || '%') OR
  lname LIKE (v_searchLnameLower || '%'))
  AND (e_flag = 'Y' OR
  it_flag = 'Y' OR
  fit_flag = 'Y'));

(Просто транспонирах вашата логика, но този case() изразът може да бъде заменен с по-чист nvl2(trim(a.column_a), a.column_a, b.data_a) ).

Знам, че казвате, че вашите заявки са по-сложни, но първото ви пристанище трябва да бъде да обмислите пренаписването им. Знам колко съблазнително е да разбиеш ядосана заявка на много бебешки SQL, съединени заедно с PL/SQL, но чистият SQL е много по-ефективен.

За да използвате колекция, най-добре е да дефинирате типовете в SQL, защото това ни дава гъвкавостта да ги използваме в SQL изрази, както и в PL/SQL.

create or replace type tab_a_row as object
    (col_a number
     , col_b varchar2(23)
     , col_c date);
/
create or replace type tab_a_nt as table of tab_a_row;
/

Ето примерна функция, която връща набор от резултати:

create or replace function get_table_a 
      (p_arg in number) 
      return sys_refcursor 
is 
    tab_a_recs tab_a_nt; 
    rv sys_refcursor; 
begin 
    select tab_a_row(col_a, col_b, col_c)  
    bulk collect into tab_a_recs 
    from table_a 
    where col_a = p_arg; 

    for i in tab_a_recs.first()..tab_a_recs.last() 
    loop 
        if tab_a_recs(i).col_b is null 
        then 
            tab_a_recs(i).col_b :=  'something'; 
        end if; 
    end loop;  

    open rv for select * from table(tab_a_recs); 
    return rv; 
end; 
/ 

И ето го в действие:

SQL> select * from table_a
  2  /

     COL_A COL_B                   COL_C
---------- ----------------------- ---------
         1 whatever                13-JUN-10
         1                         12-JUN-10

SQL> var rc refcursor
SQL> exec :rc := get_table_a(1)

PL/SQL procedure successfully completed.

SQL> print rc

     COL_A COL_B                   COL_C
---------- ----------------------- ---------
         1 whatever                13-JUN-10
         1 something               12-JUN-10

SQL>

Във функцията е необходимо да се инстанцира типа с колоните, за да се избегне изключението ORA-00947. Това не е необходимо при попълване на тип PL/SQL таблица:

SQL> create or replace procedure pop_table_a
  2        (p_arg in number)
  3  is
  4      type table_a_nt is table of table_a%rowtype;
  5      tab_a_recs table_a_nt;
  6  begin
  7      select *
  8      bulk collect into tab_a_recs
  9      from table_a
 10      where col_a = p_arg;
 11  end;
 12  /

Procedure created.

SQL> 

Накрая, насоки

„Какви трябва да бъдат насоките за кога да използвате и кога да избягвате GTT“

Глобалните времеви таблици са много добри, когато имаме нужда да споделяме кеширани данни между различни програмни единици в една и съща сесия. Например, ако имаме обща структура на отчет, генерирана от една функция, захранваща GTT, която се попълва от една от няколко процедури. (Въпреки че дори това може да бъде реализирано и с динамични референтни курсори ...)

Глобалните временни таблици също са добри, ако имаме много междинна обработка, която е твърде сложна, за да бъде решена с една SQL заявка. Особено ако тази обработка трябва да се приложи към подмножества на извлечените редове.

Но като цяло презумпцията трябва да бъде, че не е необходимо да използваме временна таблица. Така че

  1. Направете го в SQL, освен ако не е твърде трудно в който случай...
  2. ... Направете го в PL/SQL променливи (обикновено колекции), освен ако не заема твърде много памет в този случай ...
  3. ... Направете го с глобална временна таблица


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Защита на базата данни в Oracle

  2. ORA-01882:регионът на часовата зона не е намерен

  3. Защо PL/SQL не зачита привилегиите, предоставени от ролите?

  4. използвайки стойности, разделени със запетая, в клауза IN за колона NUMBER

  5. 2 начина за форматиране на число с водещи нули в Oracle