sql >> Database teknologi >  >> RDS >> Oracle

måder at undgå globale temp-tabeller i oracle

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å

  1. Gør det i SQL, medmindre det er for svært, hvilket tilfælde...
  2. ... Gør det i PL/SQL-variabler (normalt samlinger), medmindre det kræver for meget hukommelse, hvilket tilfælde...
  3. ... Gør det med en global midlertidig tabel


  1. Håndtering af fejlhåndtering, mens du kører sqlplus fra shell-scripts

  2. Sådan installeres og konfigureres MaxScale til MariaDB

  3. SQL, Unikke og Primære nøgler

  4. Kan ikke finde microsoft.sqlserver.batchparser.dll