AROUG BIDAY 2013 - Automatizar procesos de ETL con PL/SQL

4,258 views

Published on

Presentación dada en BI DAY 2013 organizado por el grupo de usuarios Oracle de Argentina (AROUG) el 12 de junio de 2013.
Difusión del evento: http://aroug.org/2013/05/bi-day-reserva-tu-lugar/

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
4,258
On SlideShare
0
From Embeds
0
Number of Embeds
6
Actions
Shares
0
Downloads
64
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

AROUG BIDAY 2013 - Automatizar procesos de ETL con PL/SQL

  1. 1. 1/49Automatizar procesos de ETL conPL/SQLIng. Nelson Calero, OCPnelson.calero@awen.com.uyAROUG BI Day – 12 de Junio 2013Buenos Aires, Argentina
  2. 2. 2/49Nelson Calero• http://www.linkedin.com/in/ncalero• Ingeniero en Computación. OCP DBA 10g. Especializado en RAC• Trabajando con herramientas Oracle y entorno linux desde 1996• DBA Oracle (desde 2001) & MySQL (desde 2005)• Instructor de Oracle University desde 2011• Co-fundador y Presidente del Grupo de Usuarios Oracle deUruguay (UYOUG) desde 2009• Orador frecuente en eventos como el Oracle OpenWorldLatinoamérica, Collaborate, OTN Tour Uruguay, JIAP, MySQLArgentina• Co-fundador y director de Awen Consulting
  3. 3. 3/49Objetivo1) Implementar de solución para cargar datos de archivos detexto a Oracle, automatizando todo lo posible, incluyendo:a) Manejo de excepcionesb) Evitar cargas duplicadas (y más controles)c) Ejecución automáticad) Informe del resultado de ejecucióne) Retoma de carga fallidas2) Ver detalles de– Instalación– Mantenimiento– Performance
  4. 4. 4/49Alternativas• Herramientas ETL– Warehouse Builder– Kettle – open source, kettle.pentaho.com• Programar usando lenguaje/framework con JDBC/ODBC– C, java, perl, python, ...• Scripts sobre funcionalidades propias de Oracle– SQL*Loader– Tablas externas– Funciones pipeline
  5. 5. 5/49¿Que vamos a usar?• Oracle Standard Edition 11.2 (>=9i)• PL/SQL• Jobs en la base de datos• Tablas externas• Archivos con datos en texto plano visibles en un directorio delservidor de base de datos• NOTA1 : solución “old school”NOTA2 : vamos a ver una solución de ejemplo basado en lasdefiniciones mostradas. Hay otras formas de implementar lomismo, dependiendo de la conveniencia de usar estasdefiniciones.
  6. 6. 6/49Tablas externasCREATE TABLE.. ORGANIZATION EXTERNAL.. LOCATION (archivo.txt)• Disponible desde la versión 9i• Acceso solo lectura con driver ORACLE_LOADER, lectura/escritura condriver ORACLE_DATAPUMP• No ocupa espacio en la base de datos. Es metadata del archivo• Permite paralelismo (tipos de datos no variables)• El archivo debe ser accesible desde el servidor de BD• Parámetros de acceso por defecto optimizados• Desde 11.2 (y 11.1.0.7) puede ejecutar comando para pre-procesarantes de leer (ej : gzip)
  7. 7. 7/49EjemploCREATE TABLE dw.paises_txt (country_code VARCHAR2(2),country_name VARCHAR2(40),country_number VARCHAR2(3))ORGANIZATION EXTERNAL (TYPE ORACLE_LOADERDEFAULT DIRECTORY datosACCESS PARAMETERS (RECORDS DELIMITED BY NEWLINEPREPROCESSOR exec:zcatFIELDS TERMINATED BY ;MISSING FIELD VALUES ARE NULL(country_code CHAR(2),country_name CHAR(40),country_number CHAR(3)))LOCATION (paises.txt.gz))REJECT LIMIT UNLIMITED;paises.txt – columnas separadas por coma
  8. 8. 8/49EjemploCREATE TABLE dw.paises_txt (country_code VARCHAR2(2),country_name VARCHAR2(40),country_number VARCHAR2(3))ORGANIZATION EXTERNAL (TYPE ORACLE_LOADERDEFAULT DIRECTORY datosACCESS PARAMETERS (RECORDS DELIMITED BY NEWLINEPREPROCESSOR exec:zcatFIELDS TERMINATED BY ;MISSING FIELD VALUES ARE NULL(country_code CHAR(2),country_name CHAR(40),country_number CHAR(3)))LOCATION (paises.txt.gz))REJECT LIMIT UNLIMITED;paises.txt – columnas separadas por coma
  9. 9. 9/49EjemploCREATE TABLE dw.paises_txt (country_code VARCHAR2(2),country_name VARCHAR2(40),country_number VARCHAR2(3))ORGANIZATION EXTERNAL (TYPE ORACLE_LOADERDEFAULT DIRECTORY datosFIELDS (country_code POSITION(01:02) CHAR,country_name POSITION(03:42) CHAR,country_number POSITION(43:45) CHAR))LOCATION (paises-pos.txt))REJECT LIMIT UNLIMITED;paises-pos.txt – columnas de ancho fijo
  10. 10. 10/49Tablas externas• Directorios :– CREATE OR REPLACE DIRECTORY datos AS /DW/datos;– CREATE OR REPLACE DIRECTORY exec AS /DW/bin;– GRANT read,write ON DIRECTORY datos TO dw;– GRANT read,execute ON DIRECTORY exec TO dw;• ACCESS Parameters: muchos. similares a SQL*Loader• Se generan archivos de log y rechazos en cada SELECT– tabla_PID.log / tabla_PID.bad– Configurable con : badfile/logfile datos:archivo
  11. 11. 11/49Tablas externas• Vista DB_EXTERNAL_LOCATIONS:SYS@XE> select * from dba_external_locations;OWNER TABLE_NAME LOCATION DIR DIRECTORY_NAME---------- -------------------- ----------------- --- ---------------DW PAISES_GZ_TXT paises.txt.gz SYS DATOSDW PAISES_POS_TXT paises-pos.txt SYS DATOSDW PAISES_TXT paises-big.txt SYS DATOSDW DT_CONTROL_TXT DT_CONTROL.TXT SYS DATOSDW PAISES_NUM_TXT paises-big.txt SYS DATOS
  12. 12. 12/49A tener en cuenta• Tablas externas con columnas DATE puede generar excepciones alleer– FECHA_ALTA POSITION (46:59) DATE "YYYY-MM-DD-HH24-MI-SS"• Registros de ancho variable no permiten paralelismo• Transformaciones se instrumentan en el select• Migrar de SQL*Loader con opcion en el controlfile– options (external_table=generate_only)– en logfile genera creación de Directory y TE, y ejemplo de insert• TE en RAC: usando ocfs2 o DBFS (desde 11.2)• Se pueden cargar LOBs– nombre de archivos en registros– archivo por cada lob– clausula COLUMN TRANSFORMS en TE
  13. 13. 13/49LOBsCREATE TABLE dw.lob_tab (Datos VARCHAR2(100),datos_clob CLOB,datos_blob BLOB)ORGANIZATION EXTERNAL(TYPE ORACLE_LOADERDEFAULT DIRECTORY datosACCESS PARAMETERS(RECORDS DELIMITED BY NEWLINEFIELDS TERMINATED BY ;MISSING FIELD VALUES ARE NULL(datos CHAR(100),archivo_clob CHAR(100),archivo_blob CHAR(100))COLUMN TRANSFORMS (datos_clob FROM LOBFILE (archivo_clob) FROM (datos) CLOB,datos_blob FROM LOBFILE (archivo_blob) FROM (datos) BLOB))LOCATION (lob-datos.txt))REJECT LIMIT UNLIMITED;
  14. 14. 14/49Tablas externas• Ejemplos– select/insert (ej1.sql)– Cargar LOBs con TE (ej-lob.sql)– Modificar atributos (ej2.sql)– Casos de error (ej3.sql)
  15. 15. 15/49Tablas externas• Ejemplos– select/insert (ej1.sql)– Cargar LOBs con TE (ej-lob.sql)– Modificar atributos (ej2.sql)– Casos de error (ej3.sql)• Error de formato en datos filtrados por tablaexterna van al archivo de rechazos (badfile)• Error de formato en datos no detectados en la tablaexterna generan error SQL al manipularlo
  16. 16. 16/49Manejo de errores (ej4.sql)BEGINInsert into DW.tablaSelect * from tabla_txt;EXCEPTIONWHEN others THEN--- capturamos errores de acceso a la tabla externa *y* de SQL al insertarIF DBMS_UTILITY.FORMAT_ERROR_STACK LIKE %KUP-04040% THENdbms_output.put_line (# no existe archivo para TABLA);ELSIF DBMS_UTILITY.FORMAT_ERROR_STACK LIKE %ORA-30653% THENdbms_output.put_line (# ERROR: problemas en datos de TABLA);ELSEdbms_output.put_line (# ERROR procesando TABLA);Raise;END IF;END;Códigos de error: http://docs.oracle.com/cd/B19306_01/server.102/b14219/kupus.htm
  17. 17. 17/49Objetivos (repaso)Cargar datos en archivos de texto a Oracle,automatizando todo lo posible, incluyendo:a) Manejo de excepcionesb) Evitar cargas duplicadas (y más controles)c) Ejecución automáticad) Informe del resultado de ejecucióne) Retoma de carga fallidas
  18. 18. 18/49Controles posiblesAlgunos imprescindibles:1) Existencia de archivos a cargar (ej-lanza.sql)– Archivo de control indicando nuevos datos (p.ej: hay_datos.txt)– utl_file.fgetattr(DATOS,l_archivo,l_existe,l_size,l_blk_size);2) Datos en archivo coincida con datos esperados (fecha)3) Evitar cargas duplicadas4) Cantidad de registros en archivo sean los esperados5) Suma de una columna coincida con la esperada (u otra operaciónarbitraria)
  19. 19. 19/49Control 1 – Existenciacreate or replace procedure p_job_carga asdeclareex BOOLEAN;flen NUMBER;bsize NUMBER;v_archivo VARCHAR2(50) := HAY_DATOS.TXT;v_dir VARCHAR2(50) := DATOS;BEGINdbms_output.enable;utl_file.fgetattr(v_dir, v_archivo, ex, flen, bsize);IF ex THEN -- existe archivo, se ejecuta carga y se quita marca de procesarp_ejecutar_carga;utl_file.fremove(v_dir, v_archivo);elseDBMS_OUTPUT.PUT_LINE(No se procesan datos, no existe archivo ||v_archivo);END IF;p_registro_informe;EXCEPTIONWHEN OTHERS THENDBMS_OUTPUT.PUT_LINE (ERROR en la ejecución del job);DBMS_OUTPUT.PUT_LINE (SQLERRM);p_registro_informe;END;
  20. 20. 20/49Control 2Datos en archivo coincida con datos esperados– Objetivo: Detectar error en manipulación de archivos de datos por operadores– Fecha (o identificación) en los datos– Archivo de control para validar : DT_CONTROL.TXTCREATE TABLE "DW"."DT_CONTROL"( "FECHA_DATOS" DATE,"TABLA" VARCHAR2(100),"NUM_REG" NUMBER(15),"COL_CTL" VARCHAR2(100),"TOT_CTL" NUMBER(15) );• Tabla externa DT_CONTROL_TXT• Esta tabla se borra con cada nueva carga– Mantenemos historia luego de cargas exitosas: "DW"."DT_CONTROL_HIST"
  21. 21. 21/49Control 3Evitar cargas duplicadas– Por archivo o global. Si permitimos cargas parciales (algún archivo da error ypero se cargan el resto) es por archivo => Fecha_dato en el archivo de datos• como nueva columna => mucha redundancia• como primer registro => select * from tabla_txt where rownum=1skip=1 para siguiente select (alter table..)– Tabla de Log de cargas anteriores: se valida que la fecha actual no existaCREATE TABLE "DW"."LOG_CARGA"( "FECHA_CARGA" DATE,"TABLA" VARCHAR2(255),"FECHA_DATOS" DATE);
  22. 22. 22/49Control 4create table tabla_bad_ext( text1 varchar2(4000) ,text2 varchar2(4000) )organization external(type oracle_loaderdefault directory datosaccess parameters (records delimited by newlineFields missing field values are null( text1 position(1:4000),text2 position(4001:8000) )) location (tabla.bad))select count(*) from tabla_bad_ext;Cantidad de registros en archivo sean los esperados– Primer registro de datos o información adicional fuera de los datos (archivo de control,usado para control 2)– Se puede validar el total cargado con ese valor, o buscar existencia de rechazos (.bad)
  23. 23. 23/49Control 5• Suma de una columna coincida con la esperada (u otraoperación arbitraria)– Permite identificar errores en la generación del archivo dedatos (p.ej: columnas fuera de orden o con datos inválidos)
  24. 24. 24/49Objetivos (repaso)Cargar datos en archivos de texto a Oracle,automatizando todo lo posible, incluyendo:a) Manejo de excepcionesb) Evitar cargas duplicadas (y más controles)c) Ejecución automáticad) Informe del resultado de ejecucióne) Retoma de carga fallidas
  25. 25. 25/49Ejecución automática• Agendar job que lance la cargavariable v_job number;exec dbms_job.submit (:v_job, p_job_carga;,sysdate, f_intervalo);commit;• Reintentar durante N días– Función en next_date f_intervalo
  26. 26. 26/49Ejecución automática-- calcula la fecha de proxima ejecucion del job de cargacreate or replace function dw.f_intervalo return date isv_mes date := trunc(sysdate,MON);beginif trunc(sysdate) between v_mes+3 and v_mes+13 then – entre el 4 y 14return trunc(sysdate)+1+1/24; -- dia siguiente a la 1:00 amelsif trunc(sysdate) > v_mes+13 then – después del 14-- mes siguiente día 4 a la 1:00 amreturn add_months(trunc(sysdate,MON)+3, 1) + 1/24;Else – antes del 4return trunc(sysdate,MON)+3 + 1/24; -- 10 del mes actual a la 1:00 amend if;End;
  27. 27. 27/49Crear informe• Varias alternativas– Generar datos en tabla temporal de log al cargar cadatabla, select como último paso– Spool en sqlplus– Escribir archivo en el servidor con paquete UTL_FILE• En lugar de insertar en tabla de log/spool• Capturar salida de dbms_output. Sirve para encapsularcódigo ya existente, y es práctico para testear. Límite de1Mb en 9.2, ilimitado desde 10.2– Buena discusión de opciones:http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:146412348066
  28. 28. 28/49Informe con dbms_output(ej-informe.sql)archivo := informe_carga_||to_char(sysdate,yyyymmdd)||.log;output_file := utl_file.fopen (DATOS, archivo, A);loopstatus := max_lines;DBMS_OUTPUT.GET_LINES ( output_table, status);FOR linenum in 1..statusLOOPBEGINutl_file.put_line (output_file, NVL (output_table(linenum),<null>));EXCEPTIONWHEN OTHERS THENutl_file.put_line (output_file, Error: linea ||linenum|| -||sqlerrm);END;END LOOP;exit when status < max_lines; -- no quedan mas lineas por leerend loop;utl_file.fclose(output_file);
  29. 29. 29/49Objetivos (repaso)Cargar datos en archivos de texto a Oracle,automatizando todo lo posible, incluyendo:a) Manejo de excepcionesb) Evitar cargas duplicadas (y más controles)c) Ejecución automáticad) Informe del resultado de ejecucióne) Retoma de carga fallidas
  30. 30. 30/49Retoma de fallasSimplificando el procedimiento de carga:– Controlar datos tabla1– Cargar tabla1– Manejo excepciones1– Controlar datos tabla2– Cargar tabla2– Manejo excepciones2– …– Controlar datos tablaN– Cargar tablaN– Manejo excepcionesN
  31. 31. 31/49Procedimiento de cargaPara evitar repetir código:– Control de datos genérico– Uso de tabla de configuración (CARGA_DEF).indica que tablas hay que cargar:• Nombre de tabla destino• Nombre de tabla externa• Tipo de carga (incremental o reemplazo)• Columna usada para control de fecha• Columna usada para control de suma
  32. 32. 32/49Procedimiento de carga-– Función para controlar integridad de archivos a cargarfunction f_control (p_tabla in varchar2,p_fecha_dato out number,p_replace out boolean)return number isBeginLee dt_carga_defControla fecha de datos sea la fecha a cargarSi tipo_carga = APPENDControla que no hayan datos de esa fecha cargadosValida cantidad de registros en archivo sean los indicadosValida columna de suma (si se indica)Retorna #registros (codigos de error son negativos)End;
  33. 33. 33/49Procedimiento de carga-– Procedimiento de carga genéricoProcedure p_carga_generica (p_tabla in varchar2, p_tabla_txt in varchar2)Beginv_reg_ctl := f_control (p_tabla, v_fecha, v_replace);Si v_reg_ctl > 0 (éxito)Si carga REPLACE => truncar tablaExecute immediate insert /*+ APPEND */ … select * from TEValidar #registros insertados sean los indicadosRegistrar carga en tabla de logArchivar (historia) registro de cargaExceptionRollback de esta tablaLoguear error y continuarEnd;
  34. 34. 34/49Procedimiento de carga-– Procedimiento de carga globalProcedure p_ejecutar_cargaBeginCargar registros de control(desde TE. Indica tablas a cargar y valores p/control)Validar que no se haya hecho una carga completa igualPor cada tabla configurada para cargarSi no hubo carga anterior incompleta de esta tablap_carga_generica (tabla);End;
  35. 35. 35/49Objetivos (repaso)Cargar datos en archivos de texto a Oracle,automatizando todo lo posible, incluyendo:a) Manejo de excepcionesb) Evitar cargas duplicadas (y más controles)c) Ejecución automáticad) Informe del resultado de ejecucióne) Retoma de carga fallidas
  36. 36. 36/49Ejecución completaRutinas involucradas:• Job en la base– f_next_date– p_job_carga• p_registro_informe• p_ejecutar_carga– f_control– p_carga_generica
  37. 37. 37/49Instalación• Directorio de datos– Creación en file system– Permisos de acceso para Oracle, y a los archivos– Creación de directorio en Oracle y permisos• Creación de tablas externas para las tablas de datos• Creación de tabla de control y externa• Creación de tabla de definiciones– Cargar definiciones• Creación de procedimientos de carga• Creación de rutinas auxiliares para job• Creación de job
  38. 38. 38/49Ejemplo• Código en crea_pck_load.sql– Revisar e instalar• Ejecución completa ok y con error– Analizar datos e informes
  39. 39. 39/49¿Cargar nuevas tablas?• Debemos:– Crear nueva tabla destino– Crear nueva tabla externa– Agregar registro de configuración– Agregar código pl/sql para carga• Se puede automatizar generando elcódigo de ambos
  40. 40. 40/49Generar códigodeclarecursor c_cols isselect owner, table_namefrom dw.dw_carga_defwhere owner=v_ownerorder by table_name;procedure p (p_str in varchar2) isbegininsert into gen_auxvalues (s_orden.nextval, p_str);end;Beginp(create or replace package ||v_owner||.k_carga is);for r_cols in c_cols loopp( procedure p_||r_cols.table_name||;);end loop;...End;set linesize 120 pagesize 0set trimspool onset feedback offspool /tmp/archivo.sqlselect datofrom gen_auxorder by orden;spool off
  41. 41. 41/49Ejemplo: crear las TE• script PL/SQL: gen-tab-txt.sql– Genera crea_tab_txt.sql• Datos delimitados. Para posicionales ocon formatos especiales hay que ajustarel código.
  42. 42. 42/49Código completo de carga• script gen-pck-load.sql– Genera crea_pck_load.sql• Mucho testing!!
  43. 43. 43/49PerformanceRecomendaciones– Definir tipo de datos en la TE para evitar transformaciones dedatos en SQL que impactan en la performance– Si hay columnas DATE en la TE, usar DATE_CACHE grande– Insertar en modo Direct Path: insert /*+ APPEND */ ...– Paralelismo es útil:• Disponible en versión Enterprise.• Hay que evaluar capacidad del storage para no saturarlo.• No es necesario separar el archivo de datos• Se habilita con la cláusula “PARALLEL N” en la creación de la TE– Optimizar el acceso a archivos de datos• si es un mapeo de red, validar enlace• no competir con acceso a datafiles
  44. 44. 44/49Performance¿Qué hacer si las cargas son lentas?– Tablas con pocos índices y muchos datos existentes:deshabilitar índices antes de cargar– Muchos índices y muchos datos son un problema– Particionamiento puede ser útil con índices locales. Esmas útil para tareas de mantenimiento posteriores (p.ej:quitar datos obsoletos) cuando las consultas lo permiten– Si hay funciones de transformación, analizar peformanceindividual– Ante dudas, SQL Trace revela donde está el problema
  45. 45. 45/49Performance – SQL traceoracle@oraculo:/DW> sqlplus / as sysdbaSQL*Plus: Release 11.2.0.2.0 Production on Wed Jun 12 01:43:22 2013Copyright (c) 1982, 2010, Oracle. All rights reserved.Connected to:Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit ProductionWith the Partitioning, OLAP, Data Mining and Real Application Testing options01:43:22 SYS@ent11g>select value from v$diag_info where name=Default Trace File;VALUE-------------------------------------------------------------------/u01/app/oracle/diag/rdbms/ent11g/ent11g/trace/ent11g_ora_8683.trc01:43:26 SYS@ent11g>alter session set sql_trace=true;Session altered.01:43:28 SYS@ent11g>select count(*) from dw.paises_pos_txt;COUNT(*)----------23901:43:31 SYS@ent11g>exitoracle@oraculo:/DW> tkprof/u01/app/oracle/diag/rdbms/ent11g/ent11g/trace/ent11g_ora_8683.trc /tmp/pp.txtTKPROF: Release 11.2.0.2.0 - Development on Wed Jun 12 01:44:02 2013Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.
  46. 46. 46/49Performance – SQL traceoracle@oraculo:/DW> less /tmp/pp.txt...SQL ID: cmzwfgsvz52pq Plan Hash: 3582886107select count(*)fromdw.paises_pos_txtcall count cpu elapsed disk query current rows------- ------ -------- ---------- ---------- ---------- ---------- ----------Parse 1 0.00 0.00 0 0 0 0Execute 1 0.00 0.01 0 24 0 0Fetch 2 0.00 0.00 0 0 0 1------- ------ -------- ---------- ---------- ---------- ---------- ----------total 4 0.00 0.02 0 24 0 1Misses in library cache during parse: 0Optimizer mode: ALL_ROWSParsing user id: SYSNumber of plan statistics captured: 1Rows (1st) Rows (avg) Rows (max) Row Source Operation---------- ---------- ---------- ---------------------------------------------------1 1 1 SORT AGGREGATE (cr=64 pr=0 pw=0 time=23669 us)4 4 4 PX COORDINATOR (cr=64 pr=0 pw=0 time=17062 us)0 0 0 PX SEND QC (RANDOM) :TQ10000 (cr=0 pr=0 pw=0 time=0 us)0 0 0 SORT AGGREGATE (cr=0 pr=0 pw=0 time=0 us)0 0 0 PX BLOCK ITERATOR (cr=0 pr=0 pw=0 time=0 us cost=8 size=0 card=8168)0 0 0 EXTERNAL TABLE ACCESS FULL PAISES_POS_TXT (cr=0 pr=0 pw=0 time=0 us cost=8 size=0card=8168)
  47. 47. 47/49Conclusiones• Esta solución requiere un esfuerzo inicial grande.Para pocas tablas y sin expectativas de modificaciones futuras,puede ser una complejidad excesiva.• Desarrollo necesita dominio de PL/SQL. El mantenimiento puederealizarlo un operador.• Esta implementación es de una solución en producción.Tomó unas 60 horas su desarrollo y puesta en funcionamiento en tressistemas de la misma empresa.• Si se tienen varias cargas distintas para automatizar, se gana muchotiempo al generar el código a partir de la configuración.
  48. 48. 48/49¿Preguntas?nelson.calero@awen.com.uy
  49. 49. 49/49Referencias• External table concepts 11.2 (utilities guide)http://docs.oracle.com/cd/E11882_01/server.112/e22490/et_concepts.htm• Managing external tables 11.2 (admin guide)http://docs.oracle.com/cd/E24693_01/server.11203/e17120/tables013.htm#ADMIN01507• Loading and Transformation 11.2 (DW guide)http://docs.oracle.com/cd/E24693_01/server.11203/e16579/transform.htm#DWHSG8312• Usos interesantes de tablas externas con preproceso:– listing files with the external table preprocessor in 11ghttp://www.oracle-developer.net/display.php?id=513– profiling trace files in 11ghttp://www.oracle-developer.net/display.php?id=516–

×