sábado, 30 de mayo de 2020

FLASHBACK TABLE DROP RENAME

SQL> connect hr     
Enter password: 
Connected.
SQL> 
SQL> drop table hr.prueba;

Table dropped.

SQL> show recyclebin;
ORIGINAL NAME RECYCLEBIN NAME OBJECT TYPE  DROP TIME
---------------- ------------------------------ ------------ -------------------
PRUEBA BIN$pt/fdz3aAjTgVQAAAAAAAQ==$0 TABLE      2020-05-30:10:04:05
SQL> 
SQL> SELECT object_name as recycle_name, original_name, type from recyclebin;


SQL> show recyclebin;
ORIGINAL NAME RECYCLEBIN NAME OBJECT TYPE  DROP TIME
---------------- ------------------------------ ------------ -------------------
PRUEBA BIN$pt/fdz3aAjTgVQAAAAAAAQ==$0 TABLE      2020-05-30:10:04:05
SQL> 
SQL> 

SQL> flashback table hr.prueba to before drop;

SQL> flashback table "BIN$pt/fdz3aAjTgVQAAAAAAAQ==$0" TO BEFORE DROP RENAME TO CAMBIO;

Flashback complete.



SQL> drop table cambio;

Table dropped.

SQL> 
SQL> show recyclebin;
ORIGINAL NAME RECYCLEBIN NAME OBJECT TYPE  DROP TIME
---------------- ------------------------------ ------------ -------------------
CAMBIO BIN$pt/fdz3jAjTgVQAAAAAAAQ==$0 TABLE      2020-05-30:10:12:10
CAMBIO BIN$pt/fdz3hAjTgVQAAAAAAAQ==$0 TABLE      2020-05-30:10:11:39
CAMBIO BIN$pt/fdz3cAjTgVQAAAAAAAQ==$0 TABLE      2020-05-30:10:11:10
SQL> 
SQL> 
SQL> flashback table "BIN$pt/fdz3hAjTgVQAAAAAAAQ==$0" to before drop;

Flashback complete.


SQL> show recyclebin;
ORIGINAL NAME RECYCLEBIN NAME OBJECT TYPE  DROP TIME
---------------- ------------------------------ ------------ -------------------
CAMBIO BIN$pt/fdz3jAjTgVQAAAAAAAQ==$0 TABLE      2020-05-30:10:12:10
CAMBIO BIN$pt/fdz3cAjTgVQAAAAAAAQ==$0 TABLE      2020-05-30:10:11:10
SQL> 
SQL> 
SQL> purge recyclebin;

Recyclebin purged.

SQL> show recyclebin;
SQL> 

PURGAR UN OB JETO DE LA PAPELERA 

SQL> show recyclebin;
ORIGINAL NAME RECYCLEBIN NAME OBJECT TYPE  DROP TIME
---------------- ------------------------------ ------------ -------------------
CAMBIO BIN$sUhShFQCW7XgVQAAAAAAAQ==$0 TABLE      2020-10-09:20:52:48
SQL> exit
Disconnected from Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production
With the Partitioning, Automatic Storage Management, OLAP, Advanced Analytics
and Real Application Testing options
[oracle@localhost ~]$ sqlplus / as sysdba

SQL*Plus: Release 12.1.0.1.0 Production on Fri Oct 9 20:53:10 2020

Copyright (c) 1982, 2013, Oracle.  All rights reserved.


Connected to:
Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production
With the Partitioning, Automatic Storage Management, OLAP, Advanced Analytics
and Real Application Testing options

SQL> purge table hr.cambio;

Table purged.

SQL> connect hr/hr;
Connected.
SQL> show recyclebin;
SQL> 

LABORATORIO FLASHBACK QUERY

LABORATORIO FLASHBACK QUERY

select employee_id,salary from hr.employees
AS OF TIMESTAMP
     TO_TIMESTAMP('2020-04-27 20:13:00', 'YYYY-MM-DD HH24:MI:SS')
where employee_id=200

--update hr.employees set salary=5000 where employee_id=200;
commit;

AS OF TIMESTAMP
     TO_TIMESTAMP('2020-04-27 20:15:00', 'YYYY-MM-DD HH24:MI:SS')
where employee_id=200


ALTER TABLE READ ONLY READ WRITE

SQL> alter table hr.prueba read only;

Table altered.

SQL> insert into hr.prueba values (1,'prueba',100,106);
insert into hr.prueba values (1,'prueba',100,106)
               *
ERROR at line 1:
ORA-12081: update operation not allowed on table "HR"."PRUEBA"


SQL> alter table hr.prueba read write;

Table altered.

viernes, 29 de mayo de 2020

PL/SQL Cache Packages Procedures Functions

sql>select owner,name,type from v$db_object_cache
where sharable_mem > 100
and owner='SYSADM'
and (type='PACKAGE' or type='PACKAGE BODY' or type='FUNCTION' or type='PROCEDURE')
and kept='NO'

sql>execute dbms_shared_pool.keep('package_name');

jueves, 28 de mayo de 2020

RESTORE POINT GOOD_DATA - FLASHBACK TABLE TO RESTORE POINT

Connected to:
Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options

SQL> create restore point good_data;
Restore point created.

SQL> show user;
USER is "SYS"
SQL> 
SQL> update prueba set salary=30000;
update prueba set salary=30000
       *
ERROR at line 1:
ORA-00942: table or view does not exist


SQL> update hr.prueba set salary=30000;

107 rows updated.

SQL> commit;

Commit complete.

SQL> flashback table hr.prueba to restore point good_data;
flashback table hr.prueba to restore point good_data
                   *
ERROR at line 1:
ORA-08189: cannot flashback the table because row movement is not enabled


SQL> alter table hr.prueba enable row movement;

Table altered.

SQL> flashback table hr.prueba to restore point good_data;

Flashback complete.

[oracle@localhost ~]$ rman target /

Recovery Manager: Release 12.1.0.1.0 - Production on Thu May 28 21:25:33 2020

Copyright (c) 1982, 2013, Oracle and/or its affiliates.  All rights reserved.

connected to target database: ORCL (DBID=1376021099)

RMAN> list restore point all;

using target database control file instead of recovery catalog
SCN              RSP Time  Type       Time      Name
---------------- --------- ---------- --------- ----
2200587                               28-MAY-20 GOOD_DATA

RMAN> drop restore point good_data;

Statement processed

RMAN> list restore point all;

SCN              RSP Time  Type       Time      Name
---------------- --------- ---------- --------- ----

RMAN> 



martes, 26 de mayo de 2020

CASE AND DECODE

CASE Expressions And Statements in Oracle

The CASE expression was first added to SQL in Oracle 8i. Oracle 9i extended its support to PL/SQL to allow CASE to be used as an expression or statement.

Related articles.

Value Match (Simple) CASE Expression

The CASE expression is like a more flexible version of the DECODE function. The value match CASE expression, or simple CASE expression, compares the value of the expression (DEPTNO), with the list of comparison expressions (10 - 40). Once it finds a match, the associated value is returned. The optional ELSE clause allows you to deal with situations where a match is not found. Notice the CASE expression is aliased as "department". This will appear as the column name.

SELECT ename, empno, deptno,
  (CASE deptno
     WHEN 10 THEN 'Accounting'
     WHEN 20 THEN 'Research'
     WHEN 30 THEN 'Sales'
     WHEN 40 THEN 'Operations'
     ELSE 'Unknown'
   END) department
FROM emp
ORDER BY ename;

The value match CASE expression is also supported in PL/SQL. The example below uses it in an assignment.

SET SERVEROUTPUT ON
DECLARE
  deptno     NUMBER := 20;
  dept_desc  VARCHAR2(20);
BEGIN 
  dept_desc := CASE deptno
                 WHEN 10 THEN 'Accounting'
                 WHEN 20 THEN 'Research'
                 WHEN 30 THEN 'Sales'
                 WHEN 40 THEN 'Operations'
                 ELSE 'Unknown'
               END;
  DBMS_OUTPUT.PUT_LINE(dept_desc);
END;
/

All possible values returned by a CASE expression must be of the same data type.

Searched CASE Expression

The searched CASE expression can be more complicated, involving multiple columns in the comparisons. Each comparison is tested in turn and the associated value returned if a match is found. Once again, there is an optional ELSE clause to deal with situations where a match is not found.

SELECT ename, empno, sal,
  (CASE
     WHEN sal < 1000 THEN 'Low'
     WHEN sal BETWEEN 1000 AND 3000 THEN 'Medium'
     WHEN sal > 3000 THEN 'High'
     ELSE 'N/A'
  END) salary
FROM emp
ORDER BY ename;

The searched CASE expression is also supported in PL/SQL.

SET SERVEROUTPUT ON
DECLARE
  sal       NUMBER := 2000;
  sal_desc  VARCHAR2(20);
BEGIN 
  sal_desc := CASE
                 WHEN sal < 1000 THEN 'Low'
                 WHEN sal BETWEEN 1000 AND 3000 THEN 'Medium'
                 WHEN sal > 3000 THEN 'High'
                 ELSE 'N/A'
              END;
  DBMS_OUTPUT.PUT_LINE(sal_desc);
END;
/

All possible values returned by a CASE expression must be of the same data type.

Value Match (Simple) CASE Statement

The CASE statements supported by PL/SQL are very similar to the CASE expressions. Notice the statement is finished with the END CASE keywords rather than just the END keyword. The PL/SQL CASE statements are essentially an alternative to IF .. THEN .. ELSIF statements. They are control structures that conditionally call blocks of code.

The value match CASE statement below runs a different block of code depending the match found.

SET SERVEROUTPUT ON
BEGIN
  FOR cur_rec IN (SELECT ename, empno, deptno FROM emp ORDER BY ename) LOOP
    DBMS_OUTPUT.PUT(cur_rec.ename || ' : ' || cur_rec.empno || ' : ' || cur_rec.deptno || ' : ');
    CASE cur_rec.deptno
      WHEN 10 THEN 
        DBMS_OUTPUT.PUT_LINE('Accounting');
      WHEN 20 THEN 
        DBMS_OUTPUT.PUT_LINE('Research');
      WHEN 30 THEN 
        DBMS_OUTPUT.PUT_LINE('Sales');
      WHEN 40 THEN 
        DBMS_OUTPUT.PUT_LINE('Operations');
      ELSE 
        DBMS_OUTPUT.PUT_LINE('Unknown');
    END CASE;
  END LOOP;
END;
/

Searched CASE Statement

As with its expression counterpart, the searched CASE statement allows multiple comparisons using mulitple variables.

SET SERVEROUTPUT ON
BEGIN
  FOR cur_rec IN (SELECT ename, empno, sal FROM emp ORDER BY ename) LOOP
    DBMS_OUTPUT.PUT(cur_rec.ename || ' : ' || cur_rec.empno || ' : ' || cur_rec.sal || ' : ');
    CASE
      WHEN cur_rec.sal < 1000 THEN 
        DBMS_OUTPUT.PUT_LINE('Low');
      WHEN cur_rec.sal BETWEEN 1000 AND 3000 THEN 
        DBMS_OUTPUT.PUT_LINE('Medium');
      WHEN cur_rec.sal > 3000 THEN 
        DBMS_OUTPUT.PUT_LINE('High');
      ELSE 
        DBMS_OUTPUT.PUT_LINE('Unknown');
    END CASE;
  END LOOP;
END;
/

sábado, 23 de mayo de 2020

FUNCIONES ORACLE LPAD - RPAD

SELECT LPAD('PEPE PEREZ',20,'0') FROM DUAL; 
SELECT RPAD('PEPE PEREZ',20,'0') FROM DUAL; 

SQL FUNDAMENTALS ROWNUM



select employee_id from hr.employees
where rownum <= 50
order by employee_id;

select rowid,rownum,employee_id from hr.employees
where rownum <= 5
order by employee_id;

select rowid,rownum,employee_id from hr.employees
where rowid='AAAWWTAAKAAAADNAAA'
order by employee_id

viernes, 22 de mayo de 2020

VERIFICAR SI LA TABLA MANEJA COMPRESION



select owner,table_name,tablespace_name,avg_row_len,compression,compress_for from dba_tables
where owner='HR';

LINUX COMPRIMIR

ZIP UNZIP

[oracle@localhost ~]$ zip trace.zip trace.log
  adding: trace.log (deflated 89%)
[oracle@localhost ~]$ ls -ltr trace*
-rw-r--r--. 1 oracle oinstall 729131 May  6 18:45 trace.log
-rw-r--r--. 1 oracle oinstall  79004 May 22 19:33 trace.zip
[oracle@localhost ~]$ unzip trace.zip
Archive:  trace.zip
replace trace.log? [y]es, [n]o, [A]ll, [N]one, [r]ename: trace1.log
error:  invalid response [trace1.lo]
replace trace.log? [y]es, [n]o, [A]ll, [N]one, [r]ename: error:  invalid response [g]
replace trace.log? [y]es, [n]o, [A]ll, [N]one, [r]ename: r
new name: trace1.log
  inflating: trace1.log              
[oracle@localhost ~]$ ls -ltr trace*
-rw-r--r--. 1 oracle oinstall 729131 May  6 18:45 trace1.log
-rw-r--r--. 1 oracle oinstall 729131 May  6 18:45 trace.log
-rw-r--r--. 1 oracle oinstall  79004 May 22 19:33 trace.zip
[oracle@localhost ~]$ 


COMANDO TAR

[oracle@localhost ~]$ tar -cvf COPIA export_2020_04_01.dmp 
export_2020_04_01.dmp
[oracle@localhost ~]$ ls -ltr COPIA
-rw-r--r--. 1 oracle oinstall 20480 May 22 19:35 COPIA
[oracle@localhost ~]$ rm export_2020_04_01.dmp
[oracle@localhost ~]$ tar -xvf COPIA
export_2020_04_01.dmp
[oracle@localhost ~]$ ls -ltr export_2020_04_01.dmp 
-rw-r--r--. 1 oracle oinstall 16384 Apr  1 20:53 export_2020_04_01.dmp
[oracle@localhost ~]$ 


SHRINK SPACE - ALTER TABLE MOVE

SQL> ALTER TABLE HR.PRUEBA ENABLE ROW MOVEMENT;

SQL> ALTER TABLE HR.PRUEBA SHRINK SPACE;

Table altered.

SQL> ALTER TABLE HR.PRUEBA SHRINK SPACE COMPACT;

SQL> ALTER TABLE HR.PRUEBA SHRINK SPACE;

SQL> ALTER TABLE HR.PRUEBA MOVE TABLESPACE EXAMPLE;

SQL> ALTER TABLE HR.PRUEBA MOVE;

TAMANO BASE DE DATOS

select DF.TOTAL/1048576 "DataFile Size Mb",
LOG.TOTAL/1048576 "Redo Log Size Mb",
CONTROL.TOTAL/1048576 "Control File Size Mb",
(DF.TOTAL + LOG.TOTAL + CONTROL.TOTAL)/1048576 "Total Size Mb" from dual,
(select sum(a.bytes) TOTAL from dba_data_files a) DF,
(select sum(b.bytes) TOTAL from v$log b) LOG,
(select sum((cffsz+1)*cfbsz) TOTAL from x$kcccf c) CONTROL
/


select sum(BYTES)/1024/1024/1024 GB from DBA_EXTENTS
/

IDENTIFICAR ROW MIGRATION

SQL> analyze table hr.prueba compute statistics;

Table analyzed.

SQL> select num_rows,avg_row_len,chain_cnt from dba_tables where owner='HR' and table_name='PRUEBA';

  NUM_ROWS AVG_ROW_LEN CHAIN_CNT
---------- ----------- ----------
       107     73 0

SQL> 


SQL> ANALYZE TABLE hr.prueba list chained rows;


UNA FORMA REORGANIZAR SERIA

SQL> alter table hr.prueba move; 


OTRA FORMA SERIA

SQL> alter table hr.prueba move tablespace example;



CREATE TABLESPACE BLOCKSIZE

NOTA: CREACION TAMAÑO BLOQUE TABLESPACE


2K < 10 COLUMNAS
4K > 10 COLUMNAS < 20 COLUMNAS
8K > 20 COLUMNAS < 100 COLUMNAS
16K > 100 COLUMNAS < 200 COLUMNAS
32 K> > 200 < 1000



SQL> CREATE TABLESPACE DATOS DATAFILE SIZE 150M;

SQL> CREATE TABLESPACE PRUEBA1 DATAFILE '/u01/app/oracle/oradata/ORCL/datafile/prueba01.dbf' SIZE 50M
BLOCKSIZE 8K;
SQL>CREATE TABLESPACE PRUEBA2 DATAFILE '/u01/app/oracle/oradata/ORCL/datafile/prueba02.dbf' SIZE 50M
BLOCKSIZE 16k;

SIN NO SE CONFIGIURA EL PARAMETRO DB_16K GENERA ERROR

CREATE TABLESPACE PRUEBA2 DATAFILE '/u01/app/oracle/oradata/ORCL/datafile/prueba02.dbf' SIZE 50M BLOCKSIEZE 16K
*
ERROR at line 1:
ORA-29339: tablespace block size 16384 does not match configured block sizes

SQL>

SQL> alter system set db_16k_cache_size=16384 scope=both;

System altered.

SQL> show parameter db_16k;

NAME				     TYPE	 VALUE
------------------------------------ ----------- ------------------------------
db_16k_cache_size		     big integer 4M
SQL> 
SQL> show parameter db_32k;

NAME				     TYPE	 VALUE
------------------------------------ ----------- ------------------------------
db_32k_cache_size		     big integer 0
SQL> 

SQL> CREATE TABLESPACE PRUEBA2 DATAFILE '/u01/app/oracle/oradata/ORCL/datafile/prueba02.dbf' SIZE 50M BLOCKSIZE 16k; 2 Tablespace created.


jueves, 21 de mayo de 2020

CLOUD ORACLE CREACION PARTICIONES

CREACION PARTICIONES

sudo fdisk -l
sudo fdisk /dev/sdb
sudo fdisk -l
sudo mkfs.ext4 /dev/sdb1
df -h
sudo mkdir /u02
sudo mount /dev/sdb1 /u02
df -h
sud vi /etc/fstab
sudo vi /etc/fstab
sudo ls -l /dev/disk/by-uuid/
255a008d-c98d-4659-9c1b-54af2e96dc80
sudo vi /etc/fstab
sudo reboot

miércoles, 20 de mayo de 2020

HINTS EXAMPLE

SELECT /*+ HINT */ FROM TABLE WHERE CONDITION;

Hay que tener en cuenta que si no es posible efectuar lo que se indica con el hint lo ignorará ejecutándose de manera normal, tampoco afectan a subconsultas en la misma sentencia SQL, cualquier hint (excepto rule) fuerzan el uso del optimizador por costes.

Algunos posibles parámetros son:

/*+ ALL_ROWS */ Ejecuta la consulta por costes y la optimiza para que consuma el menor número de recursos posibles.
/*+ FIRST_ROWS */ Ejecuta la consulta por costes la optimiza para conseguir el mejor tiempo de respuesta.
/*+ CHOOSE */ Ejecuta la consulta por costes, es decir, el optimizador se basa en las reglas básicas, pero teniendo en cuenta el estado actual de la base de datos.
/*+ RULE */ Ejecuta la consulta por reglas, es decir, el optimizador se basa en ciertas reglas para realizar las consultas. Por ejemplo, si se filtra por un campo indexado, se utilizará el índice, etc.
/*+ INDEX( tabla índice ) */ Fuerza la utilización del índice indicado para la tabla indicada.
/*+ ORDERED */ Hace que las combinaciones de las tablas se hagan en el mismo orden en que aparecen en el join.

select /*+ index(HR.EMPLOYEES EMP_EMAIL_UK)*/ * from hr.employees

where email like 'A%'


set autotrace traceonly

lunes, 18 de mayo de 2020

TKPROF

Reproduciendo carga SQL con tkprof

Por Nelson Calero Oracle ACE
Publicado en Noviembre 2016

Tkprof es un utilitario gratuito provisto por Oracle para analizar archivos de trace de sesiones. Su uso habitual es generar un resumen simple de leer cuando estamos investigando problemas de performance. Pero tkprof tiene otro uso poco conocido: generar scripts con las sentencias capturadas que pueden usarse para reproducir la carga original en otro sistema.
Antes de ver los detalles, un poco de contexto

¿Trace? ¿Testing?
¿Qué es un trace SQL? es un archivo creado en el servidor de base de datos que tiene toda la actividad que realizó una sesión. Se puede habilitar para una sesión, en toda la base o para sesiones que cumplan una combinación de servicio, módulo y acción que definamos. Si les interesa saber más sobre cómo usar SQL Trace y las diferentes formas de habilitarlo, vean este completo artículo de Arup Nanda.

¿Para qué nos puede interesar reproducir sentencias SQL? Una tarea habitual de un DBA es validar el impacto en la performance de una aplicación luego de realizar cambios. Estos pueden ser en cualquier parte de nuestra solución: hardware, configuración, datos, diseño o código de los programas.

En algunos de esos casos, cuando el código SQL que ejecuta la aplicación no cambia, una forma de evaluar el impacto es capturar las sentencias ejecutadas por la aplicación en un ambiente y luego reproducirlas en otro que tiene los cambios que queremos evaluar. De esta forma podemos comparar el uso de recursos antes y después de los cambios para la misma carga, de forma automática y sin depender de trabajo manual por parte de los usuarios de la aplicación para intentar reproducir la actividad original.

Hay muchas herramientas para esto que buscan reproducir exactamente la carga original: Oracle tiene la opción (costo extra) Real application Testing (RAT) que incluye las herramientas Oracle SQL Performance Analyzer y Oracle Database Replay.

RAT implementa varias cosas que son necesarias y difíciles de instrumentar, como reproducir la concurrencia original, escalar la carga original (para generar más o menos concurrencia), controlar los tiempos de conexión y pausa de las sesiones, y una lista larga de etcéteras muy útiles.

Si no tenemos restricciones de presupuesto, es la herramienta a utilizar.

Si estamos buscando alternativas gratuitas de hacer algo similar, con el archivo de sentencias que genera tkprof podemos hacer algo mucho más simple: ejecutar en el mismo orden en que fueron capturadas las sentencias, sin reproducir la concurrencia original ni esperar entre cada una.

Ejemplo simple
Sigue un ejemplo usando SQL*plus y datos del schema HR, que se distribuye con las instalaciones de la base, usando Oracle 12.1.0.2 en Linux x64.

Primero damos permiso al usuario HR para habilitar trace y ver datos de su sesión:

sqlplus / as sysdba
grant execute on dbms_monitor to hr;
grant select on v_$session to hr;
grant select on v_$process to hr;
 

Luego habilitamos trace y ejecutamos una sentencia:

HR@db12102/12.1.0.2> conn hr/hr   
Connected.
HR@db12102/12.1.0.2> alter session set tracefile_identifier =  'test';
Session altered.
Elapsed: 00:00:00.00
HR@db12102/12.1.0.2> EXEC  DBMS_MONITOR.session_trace_enable(waits=>TRUE, binds=>TRUE);
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.01
HR@db12102/12.1.0.2> select count(1) 
from hr.departments d, hr.locations l, hr.employees e
where d.location_id=l.location_id(+)
 and e.DEPARTMENT_ID=d.DEPARTMENT_ID(+)
 and country_id='US';
COUNT(1)
----------
68
Elapsed: 00:00:00.06
HR@db12102/12.1.0.2> EXEC DBMS_MONITOR.session_trace_disable;
PL/SQL procedure successfully completed.
Elapsed:  00:00:00.01

 

Ahora tenemos un archivo de trace, falta identificarlo en el servidor. Si no sabemos dónde encontrarlo, esta es una forma simple de ver cuál es el archivo de trace de la sesión actual:

HR@db12102/12.1.0.2> select tracefile  from v$process  where addr=(select paddr from v$session where sid=userenv('sid'));
TRACEFILE
---------------------------------------------------------------------------
/u01/app/oracle/diag/rdbms/db12102/db12102/trace/db12102_ora_7637_test.trc

 

Para generar nuestro script SQL tenemos que procesar el archivo de trace con tkprof usando el parámetro record:

[oracle@oraculo  ~]$ cd  /u01/app/oracle/diag/rdbms/db12102/db12102/trace
[oracle@oraculo trace]$ tkprof db12102_ora_7637_test.trc result.txt sys=no record=test.sql
TKPROF: Release 12.1.0.2.0 - Development on  Sun Oct 23 18:18:31 2016
Copyright (c) 1982, 2014, Oracle and/or its  affiliates. All rights reserved.
 
[oracle@oraculo trace]$ cat test.sql
BEGIN  DBMS_MONITOR.session_trace_enable(waits=>TRUE, binds=>TRUE); END; 
/
select count(1)
from hr.departments d, hr.locations l,  hr.employees e
where d.location_id=l.location_id(+)
and e.DEPARTMENT_ID=d.DEPARTMENT_ID(+)
and country_id='US' ;
BEGIN DBMS_MONITOR.session_trace_disable;  END; 
/
[oracle@oraculo  trace]$

 

Como se puede ver, el script SQL incluye todo lo ejecutado desde que habilitamos el trace.
En este ejemplo simple se incluyen las sentencias que habilitan trace porque lo hicimos sobre la misma sesión. Esto no ocurriría si tomamos trace de otras sesiones.

¿Qué se captura si las consultas usan variables bind?
Los SQL capturados van a tener también binds, por lo que tendremos que sustituirlos manualmente por los valores reales cuando queramos ejecutar el script SQL en otra base.

Sigue un ejemplo usando variables de SQL*plus como binds:

SYS@db12102/12.1.0.2> conn hr/hr
Connected.
HR@db12102/12.1.0.2> variable n varchar2(2);
HR@db12102/12.1.0.2> exec :n := 'US';
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.00


HR@db12102/12.1.0.2> alter session set tracefile_identifier =  'test3';
Session altered.
Elapsed: 00:00:00.00
HR@db12102/12.1.0.2> EXEC  DBMS_MONITOR.session_trace_enable(waits=>TRUE, binds=>TRUE);
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.01
HR@db12102/12.1.0.2> select count(1) 
from hr.departments d, hr.locations l, hr.employees e
where d.location_id=l.location_id(+)
 and e.DEPARTMENT_ID=d.DEPARTMENT_ID(+)
 and country_id=:n;
COUNT(1)
----------
68
Elapsed: 00:00:00.05
HR@db12102/12.1.0.2> exec :n := 'CA';
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.00
HR@db12102/12.1.0.2> select count(1) 
from hr.departments d, hr.locations l, hr.employees e
  where d.location_id=l.location_id(+)
 and e.DEPARTMENT_ID=d.DEPARTMENT_ID(+)
 and country_id=:n;
COUNT(1)
----------
2
Elapsed: 00:00:00.00
HR@db12102/12.1.0.2> EXEC DBMS_MONITOR.session_trace_disable;
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.01
HR@db12102/12.1.0.2> exit
Disconnected from Oracle Database 12c  Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, Oracle Label  Security, OLAP, Advanced Analytics
and Real Application Testing options


[oracle@oraculo trace]$ ls -lrt *test3*.trc | tail
-rw-rw----. 1 oracle oinstall 21088 Oct 23  18:13  
/u01/app/oracle/diag/rdbms/db12102/db12102/trace/db12102_ora_4391_test3.trc


[oracle@oraculo trace]$ tkprof db12102_ora_4391_test3.trc  result3.txt sys=no record=test3.sql
TKPROF: Release 12.1.0.2.0 - Development on  Sun Oct 23 18:14:31 2016
Copyright (c) 1982, 2014, Oracle and/or its  affiliates. All rights reserved.
 
[oracle@oraculo trace]$ cat test3.sql 
BEGIN DBMS_MONITOR.session_trace_enable(waits=>TRUE,  binds=>TRUE); END; 
/
select count(1)
from hr.departments d, hr.locations l,  hr.employees e
where d.location_id=l.location_id(+)
and e.DEPARTMENT_ID=d.DEPARTMENT_ID(+)
and country_id=:n ;
BEGIN :n := 'CA'; END; 
/
select count(1)
from hr.departments d, hr.locations l,  hr.employees e
where d.location_id=l.location_id(+)
and e.DEPARTMENT_ID=d.DEPARTMENT_ID(+)
and country_id=:n ;
BEGIN DBMS_MONITOR.session_trace_disable;  END; 
/

 

En este caso, declaramos y asignamos la variable antes de iniciar el trace, por lo que no está en el archivo generado.

Con un poco de trabajo extra podemos tomar los valores que se deben asignar a las binds del archivo de trace (db12102_ora_4391_test3.trc), y procesar el archivo SQL generado (test3.sql) para reemplazar las variables con estos valores cuando queramos reproducir la carga:

[oracle@oraculo trace]$ grep \"US\"  db12102_ora_4391_test3.trc
value="US"
value="US"
[oracle@oraculo trace]$ grep \"CA\"  db12102_ora_4391_test3.trc
value="CA"

 

¿El script generado mantiene el orden original en que fueron ejecutadas las sentencias?
Sí, el orden original en que fueron capturadas las sentencias se mantiene en el script generado sin considerar el valor del parámetro sort de tkprof en uso - éste solo afecta el reporte generado (outputfile).

[oracle@oraculo trace]$ tkprof db12102_ora_4391_test3.trc  result3.txt sys=no record=test3-sort2.sql sort=fchcnt
TKPROF: Release 12.1.0.2.0 - Development on  Mon Oct 31 18:39:36 2016
Copyright (c) 1982, 2014, Oracle and/or its  affiliates. All rights reserved.

[oracle@oraculo trace]$ cat test3-sort2.sql 
BEGIN  DBMS_MONITOR.session_trace_enable(waits=>TRUE, binds=>TRUE); END; 
/
select count(1)
from hr.departments d, hr.locations l,  hr.employees e
where d.location_id=l.location_id(+)
and e.DEPARTMENT_ID=d.DEPARTMENT_ID(+)
and country_id=:n ;
BEGIN :n := 'CA'; END; 
/
select count(1)
from hr.departments d, hr.locations l,  hr.employees e
where d.location_id=l.location_id(+)
and e.DEPARTMENT_ID=d.DEPARTMENT_ID(+)
and country_id=:n ;
BEGIN DBMS_MONITOR.session_trace_disable;  END; 
/

 

En el ejemplo anterior, a pesar de haber usado tkprof con el parámetro sort para que ordene las sentencias por cantidad de fetchs, se puede ver que el script SQL no cambia de orden. Esto se puede ver con cualquiera de las opciones de sort que generen un orden distinto al por defecto.

¿Cómo generamos el archivo SQL si la aplicación usa varias conexiones a la base de datos?
En este caso tenemos que habilitar trace a todas las sesiones y luego procesar todos los archivos. Para facilitar esta tarea, Oracle provee el utilitario trcsess que consolida todos los traces en un solo archivo manteniendo el orden de ejecución original.

El siguiente ejemplo usa un servicio para conectarse a la base de datos para identificar fácilmente las sesiones a las que vamos a habilitar trace. Esto afecta a todas las sesiones ya conectadas que lo hayan hecho mediante el servicio y a todas las nuevas que lo usen.

[oracle@oraculo  ~]$ cat $ORACLE_HOME/network/admin/tnsnames.ora 
db12102 = 
  (DESCRIPTION=
(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521))
(CONNECT_DATA=(SERVICE_NAME=db12102))
  )
[oracle@oraculo ~]$ sqlplus hr/hr@db12102
SQL*Plus: Release 12.1.0.2.0 Production on  Mon Oct 31 17:51:45 2016
Copyright (c) 1982, 2014, Oracle. All rights reserved.
Last Successful login time: Sun Oct 23 2016  18:36:14 -04:00
Connected to:
Oracle Database 12c Enterprise Edition  Release 12.1.0.2.0 - 64bit Production
With the Partitioning, Oracle Label  Security, OLAP, Advanced Analytics
and Real Application Testing options
HR@db12102/12.1.0.2> select service_name, count(1) from  v$session group by service_name;
SERVICE_NAME                                  COUNT(1)
------------------------------------------ -----------
db12102                                              1
SYS$BACKGROUND                       		    36
SYS$USERS                                            2
Elapsed: 00:00:00.01

 

Podemos ver una sola sesión conectada que usa el servicio, y otras que no lo están usando.

Abrimos otra terminal y nos conectamos usando el mismo servicio:

[oracle@oraculo  trace]$ sqlplus hr/hr@db12102
SQL*Plus: Release 12.1.0.2.0 Production on  Mon Oct 31 18:49:17 2016
Copyright (c) 1982, 2014, Oracle. All rights reserved.
Last Successful login time: Mon Oct 31 2016  17:51:46 -04:00
Connected to:
Oracle Database 12c Enterprise Edition  Release 12.1.0.2.0 - 64bit Production
With the Partitioning, Oracle Label  Security, OLAP, Advanced Analytics
and Real Application Testing options
HR@db12102/12.1.0.2> select service_name, count(1) from  v$session group by service_name;
SERVICE_NAME                                      COUNT(1)
------------------------------------------------  --------
db12102                                                  2
SYS$BACKGROUND                                          36
SYS$USERS                                                1
Elapsed: 00:00:00.03
HR@db12102/12.1.0.2> 

 

Ahora podemos habilitar SQL trace para el servicio db12102 – esto capturará la actividad de las dos sesiones ya conectadas al servicio.

HR@db12102/12.1.0.2> EXEC DBMS_MONITOR.serv_mod_act_trace_enable(service_name=>'db12102', waits=>TRUE, binds=>TRUE);
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.17
HR@db12102/12.1.0.2> variable n varchar2(2);
HR@db12102/12.1.0.2> exec :n := 'CA';
PL/SQL procedure successfully completed.

 

Ahora volvemos a la primera sesión y ejecutamos algo también:

HR@db12102/12.1.0.2> variable n varchar2(2);
HR@db12102/12.1.0.2> exec :n := 'US';
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.01
 

De nuevo vamos a la segunda sesión para ejecutar algo:

HR@db12102/12.1.0.2> select /* first */ count(1) 
from hr.departments d, hr.locations l, hr.employees e
where d.location_id=l.location_id(+)
and e.DEPARTMENT_ID=d.DEPARTMENT_ID(+)
and country_id=:n; 
COUNT(1)
----------
2
Elapsed: 00:00:00.03

  
Otra vez cambiamos a la primera sesión para ejecutar consultas:

HR@db12102/12.1.0.2> select /* second */ count(1) 
 from hr.departments d, hr.locations l, hr.employees e
 where d.location_id=l.location_id(+)
 and e.DEPARTMENT_ID=d.DEPARTMENT_ID(+)
 and country_id=:n; 
COUNT(1)
----------
68
Elapsed: 00:00:00.00
HR@db12102/12.1.0.2> exec :n := 'UY';
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.00
HR@db12102/12.1.0.2> select /* third */ count(1) 
from hr.departments d,  hr.locations l, hr.employees e
 where d.location_id=l.location_id(+)
 and e.DEPARTMENT_ID=d.DEPARTMENT_ID(+)
 and country_id=:n;  
COUNT(1)
----------
0
Elapsed: 00:00:00.00

 

Ya que tenemos actividad en ambas sesiones y mezclada en el tiempo, podemos terminar el trace. En este ejemplo simple alcanza con salir de SQL*Plus para que se escriban los archivos.

Pero no hay que olvidar deshabilitar trace, porque toda nueva sesión usando el servicio va a crear un archivo de trace si no lo hacemos.

HR@db12102/12.1.0.2> EXEC  DBMS_MONITOR.serv_mod_act_trace_disable(service_name=>'db12102');
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.01

 

Ahora debemos procesar los archivos de trace generados:

[oracle@oraculo trace]$ ls -lrt | tail
-rw-rw----. 1 oracle oinstall   275 Oct 31 18:54 db12102_ora_18587.trm
-rw-rw----. 1 oracle oinstall 19411 Oct 31 18:54 db12102_ora_18587.trc
-rw-rw----. 1 oracle oinstall   290 Oct 31 18:54 db12102_ora_22099.trm
-rw-rw----. 1 oracle oinstall 14493 Oct 31 18:54 db12102_ora_22099.trc

 

Primero veamos que se capturó, procesando cada archivo por separado con tkprof:

[oracle@oraculo trace]$ tkprof db12102_ora_18587.trc report-srv1.txt  sys=no record=test-srv1.sql
TKPROF: Release 12.1.0.2.0 - Development on  Mon Oct 31 18:55:56 2016
Copyright (c) 1982, 2014, Oracle and/or its  affiliates. All rights reserved.
 
[oracle@oraculo trace]$ tkprof db12102_ora_22099.trc report-srv2.txt  sys=no record=test-srv2.sql
TKPROF: Release 12.1.0.2.0 - Development on  Mon Oct 31 18:56:17 2016
Copyright (c) 1982, 2014, Oracle and/or its  affiliates. All rights reserved.

 

Para generar nuestro archive consolidado, primero usemos trcsess para procesar los archivos – vamos a indicar que solo queremos ver la actividad de nuestro servicio. El resultado es un nuevo trace file.

[oracle@oraculo trace]$ trcsess output=trace-all-srv.txt service=db12102 db12102_ora_18587.trc db12102_ora_22099.trc

 

El último paso es procesar el archivo generado por trcsess usando tkrpof para generar nuestro SQL final:

[oracle@oraculo trace]$ tkprof trace-all-srv.txt report-all.txt  sys=no record=all.sql
TKPROF: Release 12.1.0.2.0 - Development on  Mon Oct 31 19:01:19 2016
Copyright (c) 1982, 2014, Oracle and/or its  affiliates. All rights reserved.
[oracle@oraculo trace]$ ls -lrt | tail
-rw-rw----. 1 oracle oinstall 19411 Oct 31 18:54 db12102_ora_18587.trc
-rw-rw----. 1 oracle oinstall   290 Oct 31 18:54 db12102_ora_22099.trm
-rw-rw----. 1 oracle oinstall 14493 Oct 31 18:54 db12102_ora_22099.trc
-rw-r--r--. 1 oracle oinstall   417 Oct 31 18:55 test-srv1.sql
-rw-r--r--. 1 oracle oinstall  8659 Oct 31 18:56 report-srv1.txt
-rw-r--r--. 1 oracle oinstall   313 Oct 31 18:56 test-srv2.sql
-rw-r--r--. 1 oracle oinstall  8659 Oct 31 18:56 report-srv2.txt
-rw-r--r--. 1 oracle oinstall 32444 Oct 31 19:00 trace-all-srv.txt
-rw-r--r--. 1 oracle oinstall   730 Oct 31 19:01 all.sql
-rw-r--r--. 1 oracle oinstall 15941 Oct 31 19:01 report-all.txt

 

Podemos ver en el contenido del SQL consolidado de toda la captura que el orden de ejecución de las sentencias se respeta:

[oracle@oraculo trace]$ cat all.sql
BEGIN  DBMS_MONITOR.serv_mod_act_trace_enable(service_name=>'db12102',  waits=>TRUE, binds=>TRUE); END; 
/
BEGIN :n := 'CA'; END; 
/
BEGIN :n := 'US'; END; 
/
select /* first */ count(1)
from hr.departments d, hr.locations l,  hr.employees e
where d.location_id=l.location_id(+)
and e.DEPARTMENT_ID=d.DEPARTMENT_ID(+)
and country_id=:n ;
select /* second */ count(1)
from hr.departments d, hr.locations l,  hr.employees e
where d.location_id=l.location_id(+)
and e.DEPARTMENT_ID=d.DEPARTMENT_ID(+)
and country_id=:n ;
BEGIN :n := 'UY'; END; 
/
select /* third */ count(1)
from hr.departments d, hr.locations l, hr.employees  e
where d.location_id=l.location_id(+)
and e.DEPARTMENT_ID=d.DEPARTMENT_ID(+)
and country_id=:n ;

 

Lo podemos comparar con los SQL generados de cada trace file individual:

[oracle@oraculo trace]$ cat test-srv1.sql
BEGIN :n := 'US'; END; 
/
select /* second */ count(1)
from hr.departments d, hr.locations l,  hr.employees e
where d.location_id=l.location_id(+)
and e.DEPARTMENT_ID=d.DEPARTMENT_ID(+)
and country_id=:n ;
BEGIN :n := 'UY'; END; 
/
select /* third */ count(1)
from hr.departments d, hr.locations l,  hr.employees e
where d.location_id=l.location_id(+)
and e.DEPARTMENT_ID=d.DEPARTMENT_ID(+)
and country_id=:n ;
[oracle@oraculo trace]$ cat test-srv2.sql
BEGIN  DBMS_MONITOR.serv_mod_act_trace_enable(service_name=>'db12102',  waits=>TRUE, binds=>TRUE); END; 
/
BEGIN :n := 'CA'; END; 
/
select /* first */ count(1)
from hr.departments d, hr.locations l,  hr.employees e
where d.location_id=l.location_id(+)
and e.DEPARTMENT_ID=d.DEPARTMENT_ID(+)
and country_id=:n ;
[oracle@oraculo trace]$