sql >> Databáze >  >> RDS >> Oracle

způsoby, jak se vyhnout globálním dočasným tabulkám v oracle

Pojďme nejprve odpovědět na druhou otázku:

"proč odcházet od GTT? jsou opravdu tak špatné."

Před pár dny jsem sháněl proof of concept, který nahrál velký soubor XML (~18 MB) do XMLType. Protože jsem nechtěl ukládat XMLType trvale, zkusil jsem jej načíst do proměnné PL/SQL (paměť relace) a dočasné tabulky. Načtení do dočasné tabulky trvalo pětkrát déle než načtení do proměnné XMLType (5 sekund oproti 1 sekundě). Rozdíl je v tom, že dočasné tabulky nejsou paměťové struktury:jsou zapsány na disk (konkrétně na váš nominovaný dočasný tabulkový prostor).

Pokud chcete ukládat do mezipaměti mnoho dat, pak jejich uložení do paměti zatíží PGA, což není dobré, pokud máte mnoho relací. Jde tedy o kompromis mezi RAM a časem.

K první otázce:

"Může někdo ukázat, jak transformovat výše uvedené ukázkové dotazy na kolekce a/nebo kurzory?"

Dotazy, které zveřejníte, lze sloučit do jediného příkazu:

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

(Jednoduše jsem transponoval vaši logiku, ale tento case() příkaz lze nahradit úhlednějším nvl2(trim(a.column_a), a.column_a, b.data_a) ).

Vím, že říkáte, že vaše dotazy jsou složitější, ale vaším prvním cílem by mělo být zvážit jejich přepsání. Vím, jak svůdné je rozdělit drsný dotaz na spoustu malých SQL spojených s PL/SQL, ale čisté SQL je mnohem efektivnější.

Chcete-li použít kolekci, je nejlepší definovat typy v SQL, protože nám to poskytuje flexibilitu při jejich použití v příkazech SQL i 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;
/

Zde je ukázková funkce, která vrací sadu výsledků:

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

A tady je v akci:

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>

Ve funkci je nutné vytvořit instanci typu se sloupci, aby nedošlo k výjimce ORA-00947. To není nutné při naplňování tabulky typu 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> 

Nakonec pokyny

„Jaké by měly být pokyny, kdy používat a kdy se vyhnout GTT“

Globální dočasné tabulky jsou velmi dobré, když potřebujeme sdílet data uložená v mezipaměti mezi různými programovými jednotkami ve stejné relaci. Například pokud máme generickou strukturu sestav generovanou jedinou funkcí napájející GTT, která je vyplněna jednou z několika procedur. (I když i to by mohlo být implementováno pomocí dynamických referenčních kurzorů ...)

Globální dočasné tabulky jsou také dobré, pokud máme hodně přechodného zpracování, které je příliš komplikované na to, aby se dalo vyřešit jediným SQL dotazem. Zejména pokud je toto zpracování nutné použít na podmnožiny načtených řádků.

Ale obecně by se mělo předpokládat, že nepotřebujeme používat dočasnou tabulku. Takže

  1. Udělejte to v SQL, pokud to není příliš těžké, což je případ ...
  2. ... Udělejte to v proměnných PL/SQL (obvykle kolekce), pokud to nezabere příliš mnoho paměti, což je případ ...
  3. ... Udělejte to pomocí globální dočasné tabulky


  1. Oracle Kombinujte několik sloupců do jednoho

  2. Proč je vkládání MySQL InnoDB tak pomalé?

  3. MariaDB JSON_ARRAY_INSERT() Vysvětleno

  4. Speciální znaky v PHP / MySQL