Нека първо отговорим на втория въпрос:
"защо да се махнем от 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 заявка. Особено ако тази обработка трябва да се приложи към подмножества на извлечените редове.
Но като цяло презумпцията трябва да бъде, че не е необходимо да използваме временна таблица. Така че
- Направете го в SQL, освен ако не е твърде трудно в който случай...
- ... Направете го в PL/SQL променливи (обикновено колекции), освен ако не заема твърде много памет в този случай ...
- ... Направете го с глобална временна таблица