sql >> Base de Datos >  >> RDS >> Oracle

formas de evitar las tablas temporales globales en Oracle

Respondamos primero a la segunda pregunta:

"¿Por qué abandonar los GTT? ¿Son realmente tan malos?"

Hace un par de días estaba preparando una prueba de concepto que cargaba un archivo XML más grande (~18 MB) en un XMLType. Como no quería almacenar XMLType de forma permanente, intenté cargarlo en una variable PL/SQL (memoria de sesión) y una tabla temporal. Cargarlo en una tabla temporal tardó cinco veces más que cargarlo en una variable XMLType (5 segundos en comparación con 1 segundo). La diferencia es que las tablas temporales no son estructuras de memoria:se escriben en el disco (específicamente en su espacio de tabla temporal designado).

Si desea almacenar en caché una gran cantidad de datos, almacenarlos en la memoria estresará el PGA, lo cual no es bueno si tiene muchas sesiones. Así que es una compensación entre RAM y tiempo.

A la primera pregunta:

"¿Alguien puede mostrar cómo transformar las consultas de muestra anteriores en colecciones y/o cursores?"

Las consultas que publique se pueden fusionar en una sola declaración:

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

(Simplemente transpuse su lógica pero ese case() La declaración podría reemplazarse con un nvl2(trim(a.column_a), a.column_a, b.data_a) más limpio ).

Sé que dice que sus consultas son más complicadas, pero su primer puerto de escala debería ser considerar volver a escribirlas. Sé lo seductor que es dividir una consulta retorcida en muchos SQL pequeños unidos con PL/SQL, pero SQL puro es mucho más eficiente.

Para usar una colección, es mejor definir los tipos en SQL, porque nos da la flexibilidad de usarlos en sentencias SQL y 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;
/

Aquí hay una función de muestra, que devuelve un conjunto de resultados:

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

Y aquí está en acción:

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>

En la función es necesario instanciar el tipo con las columnas, para evitar la excepción ORA-00947. Esto no es necesario cuando se llena un tipo de tabla 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> 

Finalmente, pautas

"¿Cuáles deberían ser las pautas sobre cuándo usar y cuándo evitar los GTT"

Las tablas temporales globales son muy buenas cuando necesitamos compartir datos en caché entre diferentes unidades de programa en la misma sesión. Por ejemplo, si tenemos una estructura de informe genérica generada por una sola función que se alimenta de un GTT que se completa con uno de varios procedimientos. (Aunque incluso eso también podría implementarse con cursores de referencia dinámicos...)

Las tablas temporales globales también son buenas si tenemos mucho procesamiento intermedio que es demasiado complicado para resolverlo con una sola consulta SQL. Especialmente si ese procesamiento debe aplicarse a subconjuntos de las filas recuperadas.

Pero, en general, la presunción debe ser que no necesitamos usar una tabla temporal. Entonces

  1. Hágalo en SQL a menos que sea demasiado difícil, en cuyo caso...
  2. ... Hágalo en variables PL/SQL (normalmente colecciones) a menos que ocupe demasiada memoria, en cuyo caso...
  3. ... Hágalo con una tabla temporal global