Oracle
 sql >> Baza danych >  >> RDS >> Oracle

sposoby na uniknięcie globalnych tabel tymczasowych w Oracle

Odpowiedzmy najpierw na drugie pytanie:

„dlaczego rezygnować z GTT? Czy naprawdę są takie złe”.

Kilka dni temu podrzucałem dowód koncepcji, który ładował duży plik XML (~18 MB) do XMLType. Ponieważ nie chciałem przechowywać XMLType na stałe, spróbowałem załadować go do zmiennej PL/SQL (pamięć sesji) i tabeli tymczasowej. Załadowanie go do tabeli tymczasowej trwało pięć razy dłużej niż załadowanie go do zmiennej XMLType (5 sekund w porównaniu do 1 sekundy). Różnica polega na tym, że tabele tymczasowe nie są strukturami pamięci:są zapisywane na dysku (w szczególności wyznaczony tymczasowy obszar tabel).

Jeśli chcesz buforować dużo danych, przechowywanie ich w pamięci obciąża PGA, co nie jest dobre, jeśli masz wiele sesji. Jest to więc kompromis między pamięcią RAM a czasem.

Na pierwsze pytanie:

„Czy ktoś może pokazać, jak przekształcić powyższe przykładowe zapytania w kolekcje i/lub kursory?”

Opublikowane zapytania można połączyć w jedno oświadczenie:

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

(Po prostu transponowałem twoją logikę, ale ten case() oświadczenie może zostać zastąpione ładniejszym nvl2(trim(a.column_a), a.column_a, b.data_a) ).

Wiem, że mówisz, że Twoje zapytania są bardziej skomplikowane, ale Twoim pierwszym zadaniem powinno być rozważenie ich przepisania. Wiem, jak kuszące jest dzielenie szorstkich zapytań na wiele dziecinnych SQL połączonych razem z PL/SQL, ale czysty SQL jest o wiele bardziej wydajny.

Aby użyć kolekcji, najlepiej jest zdefiniować typy w SQL, ponieważ daje nam to elastyczność w używaniu ich w wyrażeniach SQL, a także w 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;
/

Oto przykładowa funkcja, która zwraca zestaw wyników:

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

I oto jest w akcji:

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>

W funkcji konieczne jest utworzenie instancji typu z kolumnami, aby uniknąć wyjątku ORA-00947. Nie jest to konieczne przy wypełnianiu typu tabeli 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> 

Na koniec wytyczne

„Jakie powinny być wytyczne dotyczące tego, kiedy używać, a kiedy unikać GTT”

Globalne tabele tymczasowe są bardzo dobre, gdy potrzebujemy współdzielić buforowane dane między różnymi jednostkami programu w tej samej sesji. Na przykład, jeśli mamy ogólną strukturę raportu generowaną przez pojedynczą funkcję zasilającą GTT, która jest wypełniana przez jedną z kilku procedur. (Chociaż nawet to może być również zaimplementowane za pomocą dynamicznych kursorów referencyjnych ...)

Globalne tabele tymczasowe są również dobre, jeśli mamy dużo przetwarzania pośredniego, które jest zbyt skomplikowane, aby można je było rozwiązać za pomocą pojedynczego zapytania SQL. Zwłaszcza jeśli to przetwarzanie musi zostać zastosowane do podzbiorów pobranych wierszy.

Ale generalnie powinno być założenie, że nie musimy używać tabeli tymczasowej. Więc

  1. Zrób to w SQL, chyba że jest to zbyt trudne, w którym przypadku...
  2. ... Zrób to w zmiennych PL/SQL (zwykle kolekcjach), chyba że zajmuje to zbyt dużo pamięci, w takim przypadku...
  3. ... Zrób to za pomocą globalnej tabeli tymczasowej


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. ORA-01111 w MRP w bazie danych o gotowości fizycznej

  2. Dowiedz się, jakiego symbolu waluty używa Twoja sesja w Oracle

  3. Spring Batch ORA-08177:nie można zserializować dostępu do tej transakcji podczas uruchamiania pojedynczego zadania, poziom izolacji ZSERYLIZOWANY

  4. Wywołanie niezdefiniowanej funkcji oci_connect()

  5. Jak mogę utworzyć kopię tabeli Oracle bez kopiowania danych?