sql >> Databasteknik >  >> RDS >> Oracle

sätt att undvika globala temptabeller i Oracle

Låt oss svara på den andra frågan först:

"varför gå bort från GTTs? är de verkligen så dåliga."

För ett par dagar sedan knackade jag upp ett proof of concept som laddade en stor XML-fil (~18MB) till en XMLType. Eftersom jag inte ville lagra XMLType permanent försökte jag ladda den i en PL/SQL-variabel (sessionsminne) och en temporär tabell. Att ladda den i en temporär tabell tog fem gånger så lång tid som att ladda den i en XMLType-variabel (5 sekunder jämfört med 1 sekund). Skillnaden beror på att temporära tabeller inte är minnesstrukturer:de skrivs till disk (speciellt ditt nominerade temporära tabellutrymme).

Om du vill cachelagra mycket data kommer lagring av den i minnet att stressa PGA, vilket inte är bra om du har många sessioner. Så det är en kompromiss mellan RAM och tid.

Till den första frågan:

"Kan någon visa hur man omvandlar exempelfrågorna ovan till samlingar och/eller markörer?"

Frågorna du postar kan slås samman till ett enda uttalande:

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'));

(Jag har helt enkelt överfört din logik men det case() uttalande skulle kunna ersättas med en snyggare nvl2(trim(a.column_a), a.column_a, b.data_a) ).

Jag vet att du säger att dina frågor är mer komplicerade men ditt första anrop bör vara att överväga att skriva om dem. Jag vet hur förföriskt det är att dela upp en knotig fråga i massor av baby-SQL-filer som är sammanfogade med PL/SQL, men ren SQL är mycket effektivare.

För att använda en samling är det bäst att definiera typerna i SQL, eftersom det ger oss flexibiliteten att använda dem i såväl SQL-satser 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;
/

Här är en exempelfunktion som returnerar en resultatuppsättning:

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; 
/ 

Och här är 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 är det nödvändigt att instansiera typen med kolumnerna, för att undvika undantaget ORA-00947. Detta är inte nödvändigt när du fyller i en PL/SQL-tabelltyp:

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> 

Slutligen, riktlinjer

"Vilka bör riktlinjerna vara för när du ska använda och när ska du undvika GTT's"

Globala temptabeller är mycket bra när vi behöver dela cachad data mellan olika programenheter i samma session. Till exempel om vi har en generisk rapportstruktur genererad av en enda funktion som matar ut en GTT som fylls av en av flera procedurer. (Även om även det också skulle kunna implementeras med dynamiska referensmarkörer ...)

Globala temporära tabeller är också bra om vi har mycket mellanliggande bearbetning som bara är för komplicerad för att lösas med en enda SQL-fråga. Speciellt om den bearbetningen måste tillämpas på delmängder av de hämtade raderna.

Men generellt sett bör antagandet vara att vi inte behöver använda en tillfällig tabell. Så

  1. Gör det i SQL om det inte är för svårt i vilket fall ...
  2. ... Gör det i PL/SQL-variabler (vanligtvis samlingar) om det inte tar för mycket minne, vilket fall...
  3. ... Gör det med en global tillfällig tabell


  1. Hur pg_sleep_for() fungerar i PostgreSQL

  2. datetime2 vs smalldatetime i SQL Server:Vad är skillnaden?

  3. Kan IN-operatören använda LIKE-jokertecken (%) i Oracle?

  4. Hur hittar man alla tabeller som har främmande nycklar som refererar till en viss table.column och har värden för dessa främmande nycklar?