Browse Tag: PL/SQL

Oracle Instrumentation

Introducción

¿Qué significa instrumentar una aplicación? Cuando una aplicación se ha desarrollado correctamente, proporciona una parte de instrumentación, la cuál suele estar desactivada por defecto y tiene la posibilidad de activarse en caso de querer detectar qué está haciendo dicha aplicación, cómo lo hace, … (en Oracle disponemos de SQL Trace).

Es necesario instrumentar bien una aplicación para poder detectar problemas de rendimiento, qué operaciones realiza, cuánto tiempo llevan esas operaciones, …

Código de Aplicación

Como hemos comentado, toda aplicación debería ser instrumentada, pero la más importante decisión que debería llevar a cabo el arquitecto de la aplicación no es instrumentar, sino cómo instrumentar y siempre tomar esta decisión al comienzo del desarrollo de la nueva aplicación.

Una parte muy importante a la hora de monitorizar una aplicación por parte del DBA es que se haya instrumentado las llamadas a Base de Datos, ya que podremos trazar el uso de la aplicación de forma más sencilla y rápida. Sin esta parte de instrumentación, muchas veces no vamos a saber qué módulo o acción se está ejecutando con una determinada sesión para poder monitorizar y ver qué está haciendo. Esto se suele dar sobre todo cuando las conexiones a Base de Datos se realizan a través de un pool de conexiones, ya que la Base de Datos ignora qué usuario final está usando qué sesión.

Desde el lado de la Base de Datos tenemos los siguientes atributos para poder monitorizar una aplicación (client identifier, client information, module name, action name). Estos valores pueden ser obtenidos a través de la vista v$session. Hay otras vistas (v$sql) que también contienen los atributos module y action. En la vista v$sql tenemos que tener cuidado, ya que como sabemos hay sentencias compartidas por distintos usuarios, con lo cual puede que aparezcan con module y action del usuario con el que se compartió la sentencia y no el que la ejecutó a posteriori.

Vamos a poner un par de ejemplo de cómo podemos realizar la implementación en código PL/SQL y JDBC (también podríamos realizarlo con cualquier otro tipo de código).

PL/SQL

Para realizar la instrumentación en PL/SQL podemos utilizar el siguiente código:

BEGIN
 dbms_session.set_identifier(client_id=>'moises.espinosa.es');
 dbms_application_info.set_client_info(client_info=>'Linux x86_64');
 dbms_application_info.set_module(module_name=>'script.sql',
 action_name=>'test session intstumentation');
 END;
 /

Para recuperar los datos de la instrumentación podemos utilizar las siguientes sentencias:

SELECT sys_context('userenv','client_identifier') AS client_identifier,
 sys_context('userenv','client_info') AS client_info,
 sys_context('userenv','module') AS module_name,
 sys_context('userenv','action') AS action_name
 FROM dual;
SELECT client_identifier,
 client_info,
 module AS module_name,
 action AS action_name
 FROM v$session
 WHERE sid = sys_context('userenv','sid');

JDBC

Para configurar client identifier, module name, and action name usaremos el método setEndToEndMetrics dentro de la interface OracleConnection.

El siguiente ejemplo muestra como podemos utilizarlo:

metrics = new String[OracleConnection.END_TO_END_STATE_INDEX_MAX]; metrics[OracleConnection.END_TO_END_CLIENTID_INDEX] = “moises.espinosa.es”; metrics[OracleConnection.END_TO_END_MODULE_INDEX] = “SessionAttributes.java”; metrics[OracleConnection.END_TO_END_ACTION_INDEX] = “test session instrumentation”; ((OracleConnection)connection).setEndToEndMetrics(metrics, (short)0);

Conclusión

Con este tipo de trabajos demostramos lo importante que es trabajar juntos el equipo de desarrollo con los DBA desde el comienzo del desarrollo de la aplicación, pudiendo facilitarnos unos a otros el trabajo mediante aportaciones que nos permitirán desarrollar aplicaciones de mayor calidad.

Ocultar código PL/SQL en Database con wrapper

En ocasiones nos encontramos con código PL/SQL almacenado en Base de Datos con información sensible que no queremos que nadie vea, nada más que nosotros. Oracle dispone de una utilidad (wrap.exe) la cuál puede servir para proteger la propiedad intelectual del código de los desarrolladores, ya que deja el código en un formato no legible.

Se puede invocar desde el S.O. o desde la propia Base de Datos (a partir de 10G). Vamos a ver las ambas opciones:

Imaginar que tenemos el siguiente código;

CREATE OR REPLACE procedure ADMIN.kill_session
( v_sid number, v_serial number )
as
v_varchar2 varchar2(100);
begin
execute immediate 'ALTER SYSTEM KILL SESSION '||''''|| v_sid || ',' || v_serial 
|| '''' || ' immediate;';
end;
/

Desde el S.O.:

Podemos ver el resultado de aplicar wrap.exe al procedimiento:

Ahora los subimos a Base de Datos y comprobamos que queda en un formato ilegible:

Uso del paquete DBMS_DDL para wrapping dinámico:

Este paquete contiene tres funciones sobrecargadas llamada WRAP. La más simple acepta parámetros de entrada del tipo VARCHAR2 conteniendo una sentencia PL/SQL CREATE OR REPLACE que retorna el PL/SQL ilegible. Veamos el siguiente ejemplo:

 

Esto funciona correctamente con código PL/SQL menor o igual a 32K, pero el parámetro de entrada VARCHAR2 no puede hacer frente a código más grande. Para solventar esto podremos utilizar las funciones sobrecargadas:

DBMS_DDL.WRAP(
   ddl      DBMS_SQL.VARCHAR2S,
   lb       PLS_INTEGER,
   ub       PLS_INTEGER)
  RETURN DBMS_SQL.VARCHAR2S;

DBMS_DDL.WRAP(
   ddl      DBMS_SQL.VARCHAR2A,
   lb       PLS_INTEGER,
   ub       PLS_INTEGER)
  RETURN DBMS_SQL.VARCHAR2A;

La diferencia entre ambas es el tipo DBMS_SQL.VARCHAR2S limitado a 256 bytes por línea, mientras que el tipo DBMS_SQL.VARCHAR2A mantiene un máximo de 32K por línea. Mostraré un ejemplo: