Lad os først besvare det andet spørgsmål:
"hvorfor gå væk fra GTT'erne? er de virkelig så dårlige."
For et par dage siden lavede jeg et proof of concept, som indlæste en stor XML-fil (~18MB) i en XMLType. Fordi jeg ikke ønskede at gemme XMLTypen permanent, prøvede jeg at indlæse den i en PL/SQL-variabel (sessionshukommelse) og en midlertidig tabel. At indlæse den i en midlertidig tabel tog fem gange så lang tid som at indlæse den i en XMLType-variabel (5 sekunder sammenlignet med 1 sekund). Forskellen skyldes, at midlertidige tabeller ikke er hukommelsesstrukturer:de skrives til disk (specifikt din nominerede midlertidige tablespace).
Hvis du vil cache en masse data, så vil lagring af det i hukommelsen stresse PGA, hvilket ikke er godt, hvis du har mange sessioner. Så det er en afvejning mellem RAM og tid.
Til det første spørgsmål:
"Kan nogen vise, hvordan man transformerer ovenstående eksempelforespørgsler til samlinger og/eller markører?"
De forespørgsler, du sender, kan flettes til en enkelt erklæring:
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'));
(Jeg har simpelthen omsat din logik, men den case()
sætning kunne erstattes med en pænere nvl2(trim(a.column_a), a.column_a, b.data_a)
).
Jeg ved, at du siger, at dine forespørgsler er mere komplicerede, men din første anløbshavn bør være at overveje at omskrive dem. Jeg ved, hvor forførende det er at opdele en knudret forespørgsel i masser af baby-SQL'er, der er sat sammen med PL/SQL, men ren SQL er langt mere effektivt.
For at bruge en samling er det bedst at definere typerne i SQL, fordi det giver os fleksibiliteten til at bruge dem i SQL-sætninger såvel som 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;
/
Her er en eksempelfunktion, som returnerer et resultatsæt:
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;
/
Og her er den i aktion:
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>
I funktionen er det nødvendigt at instansiere typen med kolonnerne for at undgå ORA-00947 undtagelsen. Dette er ikke nødvendigt, når du udfylder en PL/SQL-tabeltype:
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>
Til sidst retningslinjer
"Hvad skal retningslinjerne være for hvornår du skal bruge, og hvornår skal du undgå GTT'er"
Globale temp-tabeller er meget gode, når vi skal dele cachelagrede data mellem forskellige programenheder i samme session. For eksempel hvis vi har en generisk rapportstruktur genereret af en enkelt funktion, der leverer en GTT, som er udfyldt af en af flere procedurer. (Selvom selv det også kunne implementeres med dynamiske ref-markører ...)
Globale midlertidige tabeller er også gode, hvis vi har en masse mellembehandling, som bare er for kompliceret til at kunne løses med en enkelt SQL-forespørgsel. Især hvis den behandling skal anvendes på undersæt af de hentede rækker.
Men generelt burde formodningen være, at vi ikke behøver at bruge en midlertidig tabel. Så
- Gør det i SQL, medmindre det er for svært, hvilket tilfælde...
- ... Gør det i PL/SQL-variabler (normalt samlinger), medmindre det kræver for meget hukommelse, hvilket tilfælde...
- ... Gør det med en global midlertidig tabel