Archivos de la categoría Administración Oracle

En esta categoría se clasificarán las entradas relacionadas con la Administración del servidor de Base de datos Oracle.

Crear/borrar y recrear database control console en Oracle 11G

Algunas veces, debido a errores propios del instalador Oracle y/o a errores en el nombre del host (por ejemplo poniendo un “_” o un “-”) la consola database control de Oracle 11G no se instala correctamente. Por este motivo, he decidido crear esta entrada de blog para explicar a aquellos administradores de Oracle que no sepan como crearla de nuevo, borrarla o recrearla.

Para borrarla y asegurarnos de que se borra de manera adecuada lo ideal es hacer:

cargar las variables del entorno ORACLE (ORACLE_HOME, ORACLE_SID, PATH, etc…)

Logearse a sqlplus con SYS o SYSTEM como SYSDBA:

sqlplus /nolog
connect /as sysdba

Luego ejecutar lo siguiente para borrar el repositorio:

drop user sysman cascade;

drop role MGMT_USER;
drop user MGMT_VIEW cascade;
drop public synonym MGMT_TARGET_BLACKOUTS;
drop public synonym SETEMVIEWUSERCONTEXT;

Cambiarse al directorio $ORACLE_HOME/bin o %ORACLE_HOME%/bin en el caso de Windows:

Borrar la consola que se accede desde un navegador:

emca -deconfig dbcontrol db -repos drop

Una vez borrada … volverla a crear

emca -config dbcontrol db -repos create

si no la borramos pero queremos re-crearla ejecutar:

emca -config dbcontrol db -repos recreate

NOTA: cuando acabe el proceso de configuración se mostrará la URL dónde poder conectarse usando un navegador.

Añadir disco a DiskGroup con ASM en Windows

En la siguiente entrada de blog voy a explicar como añadir un nuevo disco a un diskgroup de ASM para ser utilizado por ORACLE.

Existen numerosas entradas en internet de cómo hacer esta operación bajo Linux, pero no he encontrado ninguna que lo haga bajo Windows y por este motivo he considerado necesario crear esta entrada.

Para poneros en contexto comentar que  este ejemplo se realizó en una máquina virtual  (MV) creada con Oracle Virtual Box en la que instalé Windows Server 2008 R2. La máquina constaba con un sólo disco y posteriormente añadí otro para poder usarlo con ASM. Es decir, una vez arrancada la MV y entrando en el administrador de discos de Windows tenía esto:

Lista de volúmenes actual

Cómo se puede observar en la imagen el Disco 1 que está en formato RAW es dónde está instalado ASM. Por tanto, voy a añadir otro disco al que tendré que dar también formato RAW para poderlo usar con ASM posteriormente.

Empezamos…

Ahora lo que se hace es crear el disco en la MV. (Este paso no lo he explicado porque no es el objeto de la entrada de este blog). Una vez creado arranco la MV y me arrancará Windows Server 2008 R2 en mi caso. Iré al administrador de equipos y de discos  y me debería salir la siguiente pantalla:

pant1

Como se puede observar Windows me ha detectado el nuevo disco que he añadido previamente a la MV. En mi caso marco MBR y doy a Aceptar. Quedará asi:

pant2

Lo siguiente que haremos será darle formato RAW para que posteriormente se pueda integrar en el ASM de Oracle.

pant3

Seleccionamos nuevo volumen simple …. y procedemos como explico en las siguientes imágenes:

pant4

pant5

Dejo que seleccione todo el tamaño del disco (pantalla anterior) y en la siguiente pantalla es importante marcar “no asignar una letra ….”.

pant6b

Marcamos no formatear este volumen para que nos quede el formato RAW.

pant7

pant8

al acabar el proceso debemos tener algo como:

pant9

Seguimos….

Hasta el momento sólo tenemos el disco en formato RAW pero ORACLE ASM de momento no puede verlo. Para ello, debemos ponerle una etiqueta al disco que nos permita poder agregarlo con ASM.

Vamos a entrar a ASM y mirar que es lo que vemos:

Cargando el entorno ASM, normalmente y desde la linea de comandos de Windows:

C:\> set ORACLE_SID=+ASM
C:\oracle\app\Administrador\product\11.2.0\grid\BIN>sqlplus /nolog
SQL*Plus: Release 11.2.0.1.0 Production on Mar Dic 1 14:16:29 2015
Copyright (c) 1982, 2010, Oracle.  All rights reserved.
SQL> connect /as sysasm
SQL> select group_number,path,name, total_mb, free_mb from v$asm_disk;
GROUP_NUMBER
------------
PATH
--------------------------------------------------------------------------------
NAME                             TOTAL_MB    FREE_MB
------------------------------ ---------- ----------
         1
\\.\ORCLDISKDATA0
DATA_0000                           61812      59614
SQL>  col path format a40
SQL>  set line 120
SQL>  select name, path, group_number from v$asm_disk;
NAME                           PATH                                     GROUP_NUMBER
------------------------------ ---------------------------------------- ------------
DATA_0000                      \\.\ORCLDISKDATA0   1

Cómo se puede observar, sólo vemos el disco de 61812 MB (60,36 GB) y no el que hemos añadido recientemente de 10,45 GB.

Seguidamente arrancaremos la herramienta de ORACLE que nos permite asignarle una etiqueta al disco para posteriormente poderlo visualizar desde ASM. Este paso es precisamente del que no existe demasiada documentación en Internet.

En primer lugar lo que haremos es ir al ORACLE_HOME del grid dónde se encuentre ASM. En mi caso:

C:\> cd C:\oracle\app\Administrador\product\11.2.0\grid\BIN>

Aquí ejecutar la herramienta asmtoolg:

C:\oracle\app\Administrador\product\11.2.0\grid\BIN> asmtoolg

Proceder como se indica en las imágenes:

asmtoolg1

asmtoolg2

Seleccionaremos el “candidate device”

asmtoolg3

asmtoolg4

De esta manera ya hemos configurado una etiqueta para el disco. Ahora si que lo podemos ver desde ASM. Lo comprobamos:

C:\oracle\app\Administrador\product\11.2.0\grid\BIN>sqlplus /nolog
 SQL*Plus: Release 11.2.0.1.0 Production on Mar Dic 1 14:16:29 2015
 Copyright (c) 1982, 2010, Oracle.  All rights reserved.
 SQL> connect /as sysasm
 Conectado.
 SQL> col path format a40
 SQL>  set line 120
 SQL>  select name, path, group_number from v$asm_disk;
NAME                           PATH                                     GROUP_NUMBER
 ------------------------------ ---------------------------------------- ------------                                
                                        \\.\ORCLDISKDATA1                                   0
DATA_0000                 \\.\ORCLDISKDATA0                                   1

Podemos observar que ya aparece nuestro nuevo disco ORCLDISKDATA1 y que no pertenece a ningún diskgroup ya que no tiene “NAME”. Sin embargo, el otro disco pertenece al diskgroup DATA_0000. Pues es a este diskgroup al que queremos añadir el nuevo disco. Esto se hace ejecutando la siguiente instrucción:

SQL> ALTER DISKGROUP data ADD DISK '\\.\ORCLDISKDATA1';
Diskgroup altered.

NOTA:  ”data” es el nombre de diskgroup y se saca de v$asm_diskgroup de la siguiente manera:

SQL> select name, total_mb from v$asm_diskgroup;
NAME                                   TOTAL_MB
-----------------------------  ----------------
DATA                                      61812

Saco también el tamaño del disco para identificarlo y asegurarme que la etiqueta que selecciono es la del disco que quiero.

Comprobamos la adición:

SQL>  col path format a40
SQL>  set line 120
SQL>  select name, path, group_number from v$asm_disk;
NAME                           PATH                                     GROUP_NUMBER
------------------------------ ---------------------------------------- ------------
DATA_0000                      \\.\ORCLDISKDATA0                                   1
DATA_0001                      \\.\ORCLDISKDATA1                                   1
SQL>

 

Cuando el disco se agrega al diskgroup, ASM comienza un proceso propio de rabalanceo e integra el disco al resto del espacio ocupado creando un volumen de espacio mas grande.

Para saber en que estado se encuentra ese re-balanceo de información, podemos ejecutar la siguiente consulta:

select * from v$asm_operation;
no rows selected

Cuando la consulta devuelva “no rows selected” es que ya terminó el rebalanceo. Otra manera de comprobarlo sería revisar el fichero alert de la instancia donde nos encontraremos con la información de culminación del proceso.

Así finaliza la adhesión de nuestro nuevo disco a un diskgroup existente.

¿fácil no?

 

Utilidad oerr de ORACLE

OERR es una utilidad de Oracle que extrae los mensajes de error informándote de la posible causa y recomendando acciones que se sugieren a partir de los archivos de mensajes estándar de Oracle. Esta utilidad es muy útil ya que puede extraer los errores específicos de OS que no están en los mensajes de error y códigos de Manual genéricos.

Oerr sólo funciona en sistemas Unix/Linux y se instala junto con el software de Base de datos en el directorio $ORACLE_HOME/bin.

Para saber que acciones podemos realizar cuando se produce un error Oracle que muestro un mensaje ORA- podemos ejecutar la siguiente instrucción:

$ cd $ORACLE_HOME/bin (sino lo tenemos en el PATH)
$ oerr ora 600       (Aquí poner el error ORA-NNNNN que nos haya dado)
ora-00600: internal error code, arguments: [%s], [%s], [%s], [%s], [%s], [%s], [%s], [%s]
*Cause:  This is the generic internal error number for Oracle program exceptions.  This indicates that a process has encountered an exceptional condition.
*Action: Report as a bug - the first argument is the internal error number

Consultar tabla sin que se sepa quien es el propietario

Esta entrada de blog trata de una cosa muy simple, pero que nos puede servir de ayuda para si alguna vez, queremos que algún usuario pueda realizar consultas sobre alguna tabla que no queramos que se conozca quien es el propietario. Para ello, basta con crear un sinónimo de dicha tabla y dar el permiso de consulta sobre el sinónimo.

Crear el sinónimo:

create public synonym s_tabla for usuario.tabla;

Asignar los permisos:

grant select on  s_tabla to usuario_destino;

Cuando hagamos una select del “s_tabla” veremos el contenido de “tabla” cuyo propietario es “usuario” pero no será necesario indicarlo en la consulta.

Una tontería facilona, pero que puede sernos útiles en algún momento.

 

Cómo crear el usuario ORACLE necesario para monitorizar con NAGIOS

Para poder monitorizar con NAGIOS los parámetros de Oracle, es necesario crear un usuario llamado “nagios” dentro de la BBDD que queremos monitorizar. Dependiendo de la versión de Oracle que tengamos, tendremos que asignarle unos grants diferentes para que la monitorización se pueda realizar de manera adecuada.

Para versiones 9,10G y 11G:

CREATE USER nagios IDENTIFIED BY oradbmon; -- Poner el password que deseemos
  GRANT CREATE SESSION TO nagios;
  GRANT SELECT any dictionary TO nagios; -- Este no funciona en 8i
  GRANT SELECT ON V_$SYSSTAT TO nagios;
  GRANT SELECT ON V_$INSTANCE TO nagios;
  GRANT SELECT ON V_$LOG TO nagios;
  GRANT SELECT ON SYS.DBA_DATA_FILES TO nagios;
  GRANT SELECT ON SYS.DBA_FREE_SPACE TO nagios;

Para versiones 8i (8.1.7) poner además …

 GRANT SELECT ON sys.dba_tablespaces TO nagios;
 GRANT SELECT ON dba_temp_files TO nagios;
 GRANT SELECT ON sys.v_$Temp_extent_pool TO nagios;
 GRANT SELECT ON sys.v_$TEMP_SPACE_HEADER  TO nagios;
 GRANT SELECT ON sys.v_$session TO nagios;
 GRANT SELECT ON SYS.OBJAUTH$ TO nagios;
 GRANT SELECT ON SYS.OBJ$ TO nagios;
 GRANT SELECT ON SYS.USER$ to nagios;
 GRANT SELECT ON SYS.COL$ TO nagios;
 GRANT SELECT ON SYS.TABLE_PRIVILEGE_MAP TO nagios;

Hay que tener en cuenta que para versiones 8i el privilegio SELECT ANY DICTIONARY no está soportado, y por tanto, se deben conceder de manera individual sobre los objetos del diccionario. Asimismo, el privilegio SELECT ANY TABLE  no permite el acceso a objetos del diccionario, a menos que cambiemos el parámetro…
O7_DICTIONARY_ACCESSIBILITY  de FALSE a TRUE de la siguiente manera:

alter system set o7_dictionary_accessibility=TRUE scope=spfile;

Lanzar informe de carga de repositorio de trabajo (AWR) desde sqlplus

Oracle proporciona dos scripts para producir informes de repositorio de carga de trabajo (awrrpt.sql y awrrpti.sql) que podemos ejecutar directamente desde sqlplus sin necesidad de ejecutarlos via OEM con un navegador .

Son similares en formato a los informes STATSPACK y dan la opción de formato HTML o texto plano. Los dos informes dan esencialmente la misma salida pero el awrrpti.sql te permite seleccionar una sola instancia. Los informes se pueden generar de la siguiente manera:

Conectados como sys o system ...

SQL> @$ORACLE_HOME/rdbms/admin/awrrpt.sql
SQL> @$ORACLE_HOME/rdbms/admin/awrrpti.sql

Las secuencias de comandos te pedirá que ingreses el formato del informe (html o texto), el identificador de instantánea inicial, el id instantánea final y el informe de nombre de archivo. El informe resultante o su apertura se realizará en un navegador o editor de texto en consecuencia.

El informe via html es algo parecido a la siguiente pantalla (muestro sólo una parte pequeña del informe total):

Crear una tabla con contenido mediante database link de una base de datos a otra

En la siguiente entrada de Blog, voy a explicar como crear una tabla con contenido en una base de datos Oracle accediendo a otra base de datos Oracle mediante un database Link. Además voy a mostrar que la creación de la tabla en destino puede presentar diferencias de storage dependiendo de cómo la creemos. Si queremos que sea idéntica a la de origen, tendremos que copiar sus parámetros de storage en la sentencia de creación. Esto es una manera de crear una tabla con contenido sin necesidad de utilizar las utilidades exp/imp ni expdp/impdp.

Esto es muy útil cuando queremos crear una tabla que tenemos en Desarrollo o Pre-producción y queremos pasarlo al entorno de producción.

Para el ejemplo daré por hecho que tenemos un Data Base Link creado que permite acceder a la Base de datos de destino. Un database link se crea de la siguiente manera:

CREATE PUBLIC DATABASE LINK "MY_DBLINK"
CONNECT TO USUARIO_PRUEBA
IDENTIFIED BY  "<pwd_usuario>"
USING '<cadena_conexión>'; -- Esto consiste en una cadena de conexión que debe estar en tnsnames.ora

Puedes ampliar información sobre DBLinks aqui

Para comprobar que el DBLink funciona, podemos hacer la consulta hacia la tabla que queremos copiar de la siguiente  manera:

SQL> SELECT * FROM USUARIO_PRUEBA.TABLA@MY_DBLINK;

 Ahora creamos la tabla con el contenido de la siguiente manera:

- Primero nos conectamos a la Base de datos, con el usuario que corresponda, donde queremos crear la tabla con el contenido:

sqlplus usuario_prueba@cadena_conexion

- Ahora creamos la tabla …

SQL> CREATE TABLE usuario_prueba.nombre_tabla AS SELECT * from USUARIO_PRUEBA.TABLA@MY_DBLINK;

Esta sentencia creará la tabla en el destino con su contenido, pero los parámetros de STORAGE serán los que tenga el tablespace donde esta asignado “usuario_prueba”. Es decir, no cogerá los valores de STORAGE que tiene la tabla en origen.

Ahora probaremos con otro ejemplo, donde si detallamos el STORAGE que queremos y el tablespace donde queremos ubicar la tabla.

CREATE TABLE usuario_prueba.nombre_tabla
 TABLESPACE tablespace
 PCTUSED    40
 PCTFREE    10
 INITRANS   1
 MAXTRANS   255
 STORAGE    (
 INITIAL          10016K
 NEXT             10000K
 MINEXTENTS       1
 MAXEXTENTS       499
 PCTINCREASE      0
 FREELISTS        1
 FREELIST GROUPS  1
 BUFFER_POOL      DEFAULT
 )
 LOGGING
 NOCACHE
 NOPARALLEL AS SELECT * FROM USUARIO_PRUEBA.TABLA@MY_DBLINK;

En este otro ejemplo, el storage que tendrá la tabla será el especificado en la misma sentecia CREATE TABLE, y los datos los cogerá exactamente igual que la sentencia anterior.

ORA-00054: recurso ocupado y obtenido con NOWAIT especificado o timeout vencido || Bloqueos

Este error suele aparecer cuando existen bloqueos esperando a que otro usuario termine una operación, para poder realizar la suya. Uno de los más comunes que suelen suceder  es cuando se hacen “truncate” o “drop” de tablas y no nos deja hacerlo porque las tabla/s están bloqueada/s por otros procesos de ese mismo u otros usuarios.

En el ejemplo que explico seguidamente el problema se produjo porque al llenarse un tablespace (datafile al 100%) realizando unos “inserts” en una tabla, el proceso se quedó bloqueado hasta poder hacer la inserción. En  mi caso, como podía volver a lanzar el proceso sin problema, y no quería ampliar más la ocupación del tablespace afectado. Decidí matar los procesos que estaban bloqueados y volver a lanzar la ejecución de los inserts que provocaron por error que se llenara el tablespace.

En este ejemplo sólo se va a tratar el problema del bloqueo, no se va a tener en cuenta el problema de la falta de espacio del tablespace, porque eso fue debido a otra causa, pero que fue, en parte el causante del error que os voy a explicar y cuya solución veréis en esta entrada de blog.

Entro en detalle:

Al intentar hacer un truncate de una tabla salta el error:

ORA-00054: recurso ocupado y obtenido con NOWAIT especificado o timeout vencido

SQL> truncate table <mi_tabla> ;
truncate table <mitabla>
*
ERROR at line 1:
ORA-00054: resource busy and acquire with NOWAIT specified

Esto ocurre porque se ha bloqueado uno o varios registros mediante setencias SQL. Select´s especificados como “NO WAIT” o “FOR UPDATE NOWAIT” o por una operación DDL que fue bloqueada. La solución podía pasar por hacer el commit o rollback. El commit no funcionó porque no hay espacio en el tablespace. El rollback no se probó, porque preferí matar la sesión que estaba provocando el error tal y como explico seguidamente.

En Oracle hay una vista llamada v$lock que nos indica los objetos que se encuentran en bloqueo, el identificador de usuario,  sesion y el tipo de bloqueo. Una join con la tabla dba_objects nos proporcionará ademas el nombre y tipo de los objetos bloqueados. La consulta seria como sigue:

SELECT
     decode(L.TYPE,'TM','TABLE','TX','Record(s)') TYPE_LOCK,
     decode(L.REQUEST,0,'NO','YES') WAIT,
     S.OSUSER OSUSER_LOCKER,
     S.PROCESS PROCESS_LOCKER,
     S.USERNAME DBUSER_LOCKER,
     O.OBJECT_NAME OBJECT_NAME,
     O.OBJECT_TYPE OBJECT_TYPE,
     CONCAT(' ',s.PROGRAM) PROGRAM,
     O.OWNER OWNER
 FROM v$lock l,dba_objects o,v$session s
 WHERE l.ID1 = o.OBJECT_ID AND s.SID =l.SID AND l.TYPE in ('TM','TX','UL');

Existen varios tipos de bloqueo (TM,TX,UL):

TM – DML enqueue. Bloqueos a nivel de tabla. Los bloqueos a nivel de tabla son creados cuando se ejecuta una sentencia DML del tipo: update, insert, delete, select ..for update sobre la tabla entera.

Por ejemplo:

DELETE from <mi_tabla>;
TRUNCATE <mi_tabla>;
UPDATE <mi_tabla> SET campo1 = valor;

haciendo un “delete” fue el error en este ejemplo. Por tanto tenía un bloqueo a nivel de tabla.

TX – Transaction enqueue. Bloqueos a nivel de fila. Los bloqueos a nivel de fila se crean cuando se ejecutan senencias DML contra un conjunto de registros específicos.

UL – User supplied.  Bloqueos a nivel de usuario.

Para solucionar el error:

Nos conectaremos como system a Oracle y ejecutaremos la siguiente consulta para ver si existe algún bloqueo:

 SQL> show user
 USER is "SYSTEM"
 SQL> select * from v$lock where request!=0;

Si hacemos una join con v$open_cursor podremos ver que consulta es la que se encuentra parada a la espera de que se produzca el desbloqueo para poder ejecutarse.

En la consulta siguiente podemos ver las sentencias paradas esperando a que termine un bloqueo, la sentencia que quieren ejecutar y el id de proceso que las está bloqueando:

select /*+ ordered
    no_merge(L_WAITER)
    no_merge(L_LOCKER) use_hash(L_LOCKER)
    no_merge(S_WAITER) use_hash(S_WAITER)
    no_merge(S_LOCKER) use_hash(S_LOCKER)
    use_nl(O)
    use_nl(U)
    */
    /* first the table-level locks (TM) and mixed TM/TX TX/TM */
    S_LOCKER.OSUSER OS_LOCKER,
    S_LOCKER.USERNAME LOCKER_SCHEMA,
    S_LOCKER.PROCESS LOCKER_PID,
    S_WAITER.OSUSER OS_WAITER,
    S_WAITER.USERNAME WAITER_SCHEMA,
    S_WAITER.PROCESS WAITER_PID,
    'Table lock (TM): '||U.NAME||'.'||O.NAME||
    ' - Mode held: '||
    decode(L_LOCKER.LMODE,
    0, 'None', /* same as Monitor */
    1, 'Null', /* N */
    2, 'Row-S (SS)', /* L */
    3, 'Row-X (SX)', /* R */
    4, 'Share', /* S */
    5, 'S/Row-X (SSX)', /* C */
    6, 'Exclusive', /* X */
    '???: '||to_char(L_LOCKER.LMODE))||
    ' / Mode requested: '||
    decode(L_WAITER.REQUEST,
    0, 'None', /* same as Monitor */
    1, 'Null', /* N */
    2, 'Row-S (SS)', /* L */
    3, 'Row-X (SX)', /* R */
    4, 'Share', /* S */
    5, 'S/Row-X (SSX)', /* C */
    6, 'Exclusive', /* X */
    '???: '||to_char(L_WAITER.REQUEST))
    SQL_TEXT_WAITER
from
    V$LOCK L_WAITER,
    V$LOCK L_LOCKER,
    V$SESSION S_WAITER,
    V$SESSION S_LOCKER,
    sys.OBJ$ O,
    sys.USER$ U
where S_WAITER.SID = L_WAITER.SID
    and L_WAITER.TYPE IN ('TM')
    and S_LOCKER.sid = L_LOCKER.sid
    and L_LOCKER.ID1 = L_WAITER.ID1
    and L_WAITER.REQUEST > 0
    and L_LOCKER.LMODE > 0
    and L_WAITER.ADDR != L_LOCKER.ADDR
    and L_WAITER.ID1 = O.OBJ#
    and U.USER# = O.OWNER#
union
    select /*+ ordered
        no_merge(L_WAITER)
        no_merge(L_LOCKER) use_hash(L_LOCKER)
        no_merge(S_WAITER) use_hash(S_WAITER)
        no_merge(S_LOCKER) use_hash(S_LOCKER)
        no_merge(L1_WAITER) use_hash(L1_WAITER)
        no_merge(O) use_hash(O)
        */
        /* now the (usual) row-locks TX */
        S_LOCKER.OSUSER OS_LOCKER,
        S_LOCKER.USERNAME LOCKER_SCHEMA,
        S_LOCKER.PROCESS LOCK_PID,
        S_WAITER.OSUSER OS_WAITER,
        S_WAITER.USERNAME WAITER_SCHEMA,
        S_WAITER.PROCESS WAITER_PID,
        'TX: '||O.SQL_TEXT SQL_TEXT_WAITER
    from
        V$LOCK L_WAITER,
        V$LOCK L_LOCKER,
        V$SESSION S_WAITER,
        V$SESSION S_LOCKER,
        V$_LOCK L1_WAITER,
        V$OPEN_CURSOR O
    where S_WAITER.SID = L_WAITER.SID
        and L_WAITER.TYPE IN ('TX')
        and S_LOCKER.sid = L_LOCKER.sid
        and L_LOCKER.ID1 = L_WAITER.ID1
        and L_WAITER.REQUEST > 0
        and L_LOCKER.LMODE > 0
        and L_WAITER.ADDR != L_LOCKER.ADDR
        and L1_WAITER.LADDR = L_WAITER.ADDR
        and L1_WAITER.KADDR = L_WAITER.KADDR
        and L1_WAITER.SADDR = O.SADDR
        and O.HASH_VALUE = S_WAITER.SQL_HASH_VALUE
/

Pero sino devuelve nada, que era lo que me pasaba a mi, y como el error me lo generaba un delete o un truncate, tuve que ejecutar la siguiente consulta para ver que era lo que tenía que “matar”.

SQL> SELECT mode_held FROM dba_dml_locks where OWNER='<mi_usuario>';
MODE_HELD
-------------
Row-X (SX)
Row-X (SX)
Row-X (SX)

Seguidamente podía listar los bloqueos que ocurrían en ese momento en la base de datos.Y  por medio de los campos LMODE y REQUEST saber de que tipo son :

none
null (NULL)
row-S (SS)
row-X (SX)
share (S)
S/Row-X (SSX)
exclusive (X)

SELECT oracle_username || ' (' || s.osuser || ')' username
    ,  s.sid || ',' || s.serial# sess_id
    ,  owner || '.' || object_name object
    ,  object_type
    ,  decode( l.block
       ,       0, 'Not Blocking'
       ,       1, 'Blocking'
       ,       2, 'Global') status
    ,  decode(v.locked_mode
      ,       0, 'None'
      ,       1, 'Null'
      ,       2, 'Row-S (SS)'
      ,       3, 'Row-X (SX)'
      ,       4, 'Share'
      ,       5, 'S/Row-X (SSX)'
      ,       6, 'Exclusive', TO_CHAR(lmode)) mode_held
FROM v$locked_object v,dba_objects d,v$lock l,v$session s
WHERE v.object_id = d.object_id
   and v.object_id = l.id1
   and v.session_id = s.sid
ORDER BY oracle_username,session_id
/

Sale algo como …

Intento matarlo …

SQL> alter system kill session '215,2774';
alter system kill session '215,2774'
*
ERROR at line 1:
ORA-00031: session marked for kill

Pruebo entonces con immediate y si me funciona.

alter system kill session '215,2774' immediate;

Pero si lo anterior fallase buscaría por medio de esta SQL el  SPID que es el número de proceso de Linux/unix que usaría para matar el proceso a nivel de S.O.

SELECT s.sid, p.spid, s.osuser, s.program
FROM   v$process p, v$session s
WHERE  p.addr = s.paddr;

La consulta anterior me muestra todos los procesos, buscaría el SID del proceso que quiero matar y me anotaría el campo SPID que es el que definitivamente usaré para matar el proceso. Pero si quiero sólo buscar el SID de la que quiero matar, ejecutaría:

SELECT s.sid, p.spid, s.osuser, s.program
FROM   v$process p, v$session s
WHERE  p.addr = s.paddr and s.sid = '215'; --> SID basado en mi ejemplo

Para saber cual es el SPID busco con el campo SID que me salia en la primera consulta. Es el primer valor antes de la “,” que uso en el” alter kill session …”

Para matar el proceso a nivel de S.O en mi caso un Linux. Se hace así:

Conectado como root al linux …

# ps -ef |grep  <SPID> --> Donde SPID es el número de proceso
# kill -9 <SPID>

Que GRANT se puede asignar en función del objeto destino en ORACLE

Según el objeto de que se trate, en Oracle podemos dar los siguientes privilegios:

Tables: select, insert, update, delete, alter, debug, flashback, on commit refresh, query rewrite, references, all
Views: select, insert, update, delete, under, references, flashback, debug
Sequence: alter, select
Packages, Procedures, Functions (Java classes, sources…): execute, debug
Materialized Views: delete, flashback, insert, select, update
Directories: read, write
Libraries: execute
User defined types: execute, debug, under
Operators: execute
Indextypes: execute

 

Manipular una tabla de un entorno Oracle desde otro entorno Oracle mediante DBLINK

Probablemente como administradores de Oracle nos habrán solicitado lo siguiente:

Querer consultar o modificar una tabla que está en un Servidor Oracle con un usuario que está en otro servidor Oracle.

Para poder realizar esta tarea, basta con crear un dblink entre ambas bases de datos y crearlo de manera PUBLIC y posteriormente asignar los privilegios(GRANT) de la tabla que queremos poder ver a PUBLIC. Dicha asignación de permisos a PUBLIC la realizaremos en el servidor Oracle donde está la tabla que queremos ver. Para ver que tipo de GRANT podemos asignar puedes consultar esta entrada de blog.

Ejemplo:

En el servidor “origen” creamos el dblink public:

CREATE PUBLIC DATABASE LINK "DBLINK_DESTINO"
CONNECT TO SYSTEM --> o el usuario que queramos usar
IDENTIFIED BY "<pwd>"
USING 'CADENA_CONEXION_DESTINO'; --> que existirá en tnsnames.ora 
del servidor Origen y donde se especifica el servidor, puerto, etc...
donde conectaremos cuando hagamos las consultas

Luego en el servidor “destino”:

Ejecutaremos desde sqlplus por ejemplo y con el propietario de la tabla en cuestión:

GRANT ALL ON <nombre_propietario>.<nombre_tabla> TO PUBLIC;

Para mejorar lo anterior y evitar tener que escribir el nombre del propietario en las consultas, podemos crear un sinónimo de esta manera:

CREATE PUBLIC SYNONYM <nombre_tabla> FOR <nombre_propietario>.<nombre_tabla>;

Lo importante de las sentencias anteriores es especificar “PUBLIC” de esta manera los privilegios se hacen disponibles a todos los usuarios de la base de datos. Y mediante el dblink, también lo haces disponibles a aquellos usuarios que puedan conectarse mediante ese dblink, que en este ejemplo son todos.