sql >> Database >  >> RDS >> Oracle

manieren om globale tijdelijke tabellen in oracle te vermijden

Laten we eerst de tweede vraag beantwoorden:

"Waarom weggaan van de GTT's? zijn ze echt zo slecht."

Een paar dagen geleden was ik bezig met een proof of concept dat een groot XML-bestand (~18 MB) in een XMLType laadde. Omdat ik het XMLType niet permanent wilde opslaan, heb ik geprobeerd het in een PL/SQL-variabele (sessiegeheugen) en een tijdelijke tabel te laden. Het laden in een tijdelijke tabel duurde vijf keer zo lang als het laden in een XMLType-variabele (5 seconden in plaats van 1 seconde). Het verschil is dat tijdelijke tabellen geen geheugenstructuren zijn:ze worden naar schijf geschreven (met name de door u aangewezen tijdelijke tabelruimte).

Als je veel gegevens in de cache wilt opslaan, zal het opslaan in het geheugen de PGA belasten, wat niet goed is als je veel sessies hebt. Het is dus een afweging tussen RAM en tijd.

Op de eerste vraag:

"Kan iemand laten zien hoe de bovenstaande voorbeeldquery's kunnen worden omgezet in verzamelingen en/of cursors?"

De zoekopdrachten die u plaatst, kunnen worden samengevoegd tot één enkele verklaring:

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

(Ik heb eenvoudig uw logica omgezet, maar dat case() statement kan worden vervangen door een netter nvl2(trim(a.column_a), a.column_a, b.data_a) ).

Ik weet dat je zegt dat je vragen ingewikkelder zijn, maar je eerste aanspreekpunt zou moeten zijn om te overwegen ze te herschrijven. Ik weet hoe verleidelijk het is om een ​​lastige query op te splitsen in veel baby-SQL's die aan elkaar zijn genaaid met PL/SQL, maar pure SQL is veel efficiënter.

Om een ​​collectie te gebruiken, is het het beste om de typen in SQL te definiëren, omdat het ons de flexibiliteit geeft om ze zowel in SQL-statements als in PL/SQL te gebruiken.

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

Hier is een voorbeeldfunctie die een resultatenset retourneert:

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

En hier is het in actie:

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>

In de functie is het noodzakelijk om het type met de kolommen te instantiëren, om de ORA-00947-uitzondering te vermijden. Dit is niet nodig bij het invullen van een 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> 

Tot slot, richtlijnen

"Wat zouden de richtlijnen moeten zijn over wanneer te gebruiken en wanneer GTT's te vermijden"

Globale tijdelijke tabellen zijn erg goed wanneer we gegevens in de cache tussen verschillende programma-eenheden in dezelfde sessie moeten delen. Bijvoorbeeld als we een generieke rapportstructuur hebben die wordt gegenereerd door een enkele functie die wordt gevoed door een GTT die wordt ingevuld door een van de verschillende procedures. (Hoewel zelfs dat ook zou kunnen worden geïmplementeerd met dynamische ref-cursors ...)

Globale tijdelijke tabellen zijn ook goed als we veel tussentijdse verwerking hebben die gewoon te ingewikkeld is om op te lossen met een enkele SQL-query. Vooral als die verwerking moet worden toegepast op subsets van de opgehaalde rijen.

Maar in het algemeen zou de veronderstelling moeten zijn dat we geen tijdelijke tabel hoeven te gebruiken. Dus

  1. Doe het in SQL, tenzij het te moeilijk is, in welk geval ...
  2. ... Doe het in PL/SQL-variabelen (meestal collecties) tenzij het te veel geheugen in beslag neemt, in welk geval ...
  3. ... Doe het met een wereldwijde tijdelijke tabel


  1. Onjuiste sortering/sortering/volgorde met spaties in Postgresql 9.4

  2. Belang van varchar-lengte in MySQL-tabel

  3. De schoonste manier om een ​​SQL-string in Java te bouwen

  4. Indexen in MySQL begrijpen:deel één