jueves, 2 de diciembre de 2010

Claúsula SELECT INTO

Se utiliza para almacenar lo que retorna el select en variables predefinidas.

A modo de ejemplo

SQL> declare
1 var dual.dummy%type;
2 begin
3 select dummy into var
4 from dual;
5
6 dbms_output.put_line('Name: '||var);
7 end;
8 /


En este caso lo que devuelve el select, es decir el valor de la columna “dummy”, va a parar a la variable de nombre “var” que fue definida con el tipo de dato dual.dummy%type, es decir que adopta el tipo de dato de la columna dummy de la tabla dual.

Otra forma de utilizarlo es cuando se devuelve toda una fila, es decir:

SQL> declare
1 var dual%rowtype;
2 begin
3 select * into var
4 from dual;
5
6 dbms_output.put_line('Name: '||var.dummy);
7 end;
8 /


En este caso, dentro de la variable var tenemos toda la fila devuelta por el select, y a cada campo de la fila que devolvió lo podemos acceder mediante ., como es el caso de var.dummy.

Cabe aclarar que también podemos utilizar variables de los tipos de datos que nos provee la base, por ejemplo varchar2, integer, clob, etc.

Aunque como estamos viendo con esta sentencia, solo podemos devolver una fila, lo que si podemos es devolver múltiples columnas y asignarlas a múltiples variables. Por ejemplo

SQL> declare
1 var1 prueba.columna1%type;
2 var2 prueba.columna2%type;
3 begin
4 select columna1, columna2 into col1, col2
5 from prueba;
6
7 dbms_output.put_line('Name: '||var1||''||var2||);
8 end;
9 /


Si devolviésemos más de 1 fila en nuestro select, tendríamos el siguiente error:

declare
*
ERROR at line 1:
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at line 4


Otro posible error se presentaría en el caso de que nuestro select no devuelva filas


declare
*
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at line 4

Cabe aclarar que ambos errores se puede salvar dentro de nuestro PL/SQL con la estructura “WHEN …. THEN”

Espero les haya servido

Saludos!
Gondalf.

viernes, 15 de octubre de 2010

Library cache lock

Este post si bien es cortito creo que es de bastante de utilidad.

Con los siguientes querys vamos a ser capaces de identificar las sesiones que están generando el evento “Library cache lock”

SQL> select saddr from v$session where sid in (select sid from v$session_wait where event like 'library cache lock');

Sesión Bloqueante

SQL> SELECT SID,USERNAME,TERMINAL,PROGRAM FROM V$SESSION
2 WHERE SADDR in

3 (SELECT KGLLKSES FROM X$KGLLK LOCK_A

4 WHERE KGLLKREQ = 0
5 AND EXISTS (SELECT LOCK_B.KGLLKHDL FROM X$KGLLK LOCK_B
6 WHERE KGLLKSES =
'el saddr del primer query' /* BLOCKED SESSION */
7 AND LOCK_A.KGLLKHDL = LOCK_B.KGLLKHDL
8 AND KGLLKREQ > 0)
9 );

Sesión Bloqueada

SQL> SELECT SID,USERNAME,TERMINAL,PROGRAM FROM V$SESSION
2 WHERE SADDR in

3 (SELECT KGLLKSES FROM X$KGLLK LOCK_A

4 WHERE KGLLKREQ > 0
5 AND EXISTS (SELECT LOCK_B.KGLLKHDL FROM X$KGLLK LOCK_B
6 WHERE KGLLKSES =
'el saddr del primer query' /* BLOCKING SESSION */
7 AND LOCK_A.KGLLKHDL = LOCK_B.KGLLKHDL
8 AND KGLLKREQ = 0)
9 );

Espero les haya servido.

Saludos!
Gondalf.


lunes, 27 de septiembre de 2010

Insert sobre una columna CLOB

Paso 1) Creamos una tabla modo de prueba (que contenga una columna CLOB)

SQL> CREATE TABLE prueba
2 (titulo VARCHAR2(40),
3 author VARCHAR2(40),
4 texto CLOB);

Table created.


Paso
2) Realizamos el insert que queremos realizar, llamando a la función EMPTY_CLOB() la cual deja un puntero vacio a un objeto CLOB.

SQL> INSERT INTO prueba VALUES ('Hobbit','Tolkien',EMPTY_CLOB());

1 row created.

SQL> commit;


Paso
3) Updeteamos la columna CLOB utilizando PL/SQL

DECLARE
my_text_handle CLOB;
my_buffer VARCHAR2(32767);
my_add_amt NUMBER := 0;
my_offset INTEGER := 1;

BEGIN
my_buffer := 'prueba con clob';
my_add_amt := length(my_buffer);

SELECT text
INTO my_text_handle
FROM prueba
WHERE title = 'Hobbit' FOR UPDATE;

DBMS_LOB.WRITE(my_text_handle, my_add_amt, my_offset, my_buffer);

COMMIT;

END;

PL/SQL procedure successfully completed.

SQL> select texto from prueba;

TEXT
-----------------------
Prueba con clob

Espero les haya servido

Saludos!
Gondalf

jueves, 16 de septiembre de 2010

ORA-16826: apply service state is inconsistent with the DelayMins property

Quería compartir con uds la solución a este particular error que se genera al utilizar Dataguard.

El origen del error está asociado a dos posibles causas:

1- El “Apply service” se levantó con la especificación de la opción “real time apply” o con la opción NODELAY siempre que el parámetro DelayMins es mayor a 0

2- El “Apply service” se levantó sin la especificación de la opción “real time apply” o sin la opción NODELAY siempre que el parámetro DelayMins es 0

Pues bien, sabiendo ahora como se origina el error podemos decir que la solución es bastante sencilla, lo único que necesitamos realizar es poner la configuración del dataguard bróker en el estado disable para luego hacer un reenable del mismo.

A continuación mostraremos los pasos a seguir:

Paso 1: Nos conecatamos al bróker

testbd@serverTEST ] dgmgrl

DGMGRL for HPUX: Version 10.2.0.4.0 - 64bit Production

Copyright (c) 2000, 2005, Oracle. All rights reserved.

Welcome to DGMGRL, type "help" for information.

DGMGRL> connect sys
Password:
Connected.
DGMGRL>

Paso 2: Ponemos en disable la configuración

DGMGRL> disable configuration
Disabled.

Paso 3: Ponemos en enable nuevamente la configuracion y el error desaparecerá

DGMGRL> enable configuration
Enabled.


En este momento cuando hagan un “show configuration” verán que el estado de la misma es SUCCESS.

Espero les haya servido

Saludos!
Gondalf

viernes, 20 de agosto de 2010

Creación de un SQL Tuning Advisor

==================================
= Eliminamos la tarea de tuning
==================================

exec dbms_sqltune.drop_tuning_task('task1');


==================================
= Creamos la tarea de tuning
==================================

DECLARE
tarea_tuning VARCHAR2(30);
sql CLOB;
BEGIN
sql := 'SELECT * from dual';
tarea_tuning := DBMS_SQLTUNE.CREATE_TUNING_TASK(
sql_text => sql,
user_name => USER,
scope => 'COMPREHENSIVE',
time_limit => 60,
task_name => 'task1',
description => 'prueba de tarea de tuning');
END;
/

/* hay un parametro mas de bind_list */


==================================
= Verificamos que la tarea este creada
==================================

SELECT task_name FROM DBA_ADVISOR_LOG WHERE owner = USER;


======================================
= Ejecutamos la tarea
======================================

BEGIN
DBMS_SQLTUNE.EXECUTE_TUNING_TASK( task_name => 'task1' );
END;
/


===================================
= Controlamos el estado de la tarea
===================================

SELECT task_id, status FROM USER_ADVISOR_TASKS WHERE task_name = 'task1';


======================================
= Controlamos el progreso del SQL Tuning Advisor
======================================

SELECT sofar, totalwork
FROM V$ADVISOR_PROGRESS
WHERE task_id = (SELECT task_id FROM USER_ADVISOR_TASKS WHERE task_name = 'task1');


=====================================
= Mostramos el resultado del SQL Tuning Advisor
=====================================

SELECT DBMS_SQLTUNE.REPORT_TUNING_TASK( 'task1') FROM DUAL;

Numero del día

A muchos les habrá pasado que de acuerdo a como se conecten a la base de datos, sea desde una terminal, desde el server, a través de un ODBC cambia la manera en que Oracle les devuelve el numero de día de una fecha en particular.

Esto sucede ya que una terminal puede tomar otro NLS_LANG distinto al del servidor.

A continuación vamos a ver como cambia el numero de día (por lo general se utiliza el domingo o el lunes como 1) de acuerdo al cambio de parámetro en el NLS_LANG


ora1@test ] export NLS_LANG='AMERICAN';
ora1@test ] sqlplus / as sysdba

SQL*Plus: Release 10.2.0.4.0 - Production on Mon Aug 20 10:35:15 2005
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.

Connected to:
Oracle9i Enterprise Edition Release 10.2.0.4.0 - Production
With the Partitioning, Oracle Label Security, OLAP and Oracle Data Mining options
JServer Release 10.2.0.4.0 - Production

SQL> select to_char(sysdate, 'D') from dual;

T
-
2


ora1@test ] export NLS_LANG='ENGLISH'
ora1@test ] sqlplus / as sysdba

SQL*Plus: Release 10.2.0.4.0 - Production on Mon Aug 20 10:40:43 2010
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.

Connected to:
Oracle10g Enterprise Edition Release 10.2.0.4.0 - Production
With the Partitioning, Oracle Label Security, OLAP and Oracle Data Mining options
JServer Release 10.2.0.4.0 - Production

SQL> select to_char(sysdate, 'D') from dual;

T
-
1


Espero les haya servido

Saludos!
Gondalf.

jueves, 10 de junio de 2010

Resultado de un query de varias filas concatenadas en una

La idea de este post es acercarles una función que quizás en algún momento les sea de utilidad.

El propósito de la función es concatenar el resultado de un query que devolvió varias filas en solo 1,
la función es la siguiente:

CREATE OR REPLACE FUNCTION concatfilas(qry IN VARCHAR2) RETURN VARCHAR2 IS
filaFinal VARCHAR2(4000);
result VARCHAR2(4000);
cur sys_refcursor;
BEGIN OPEN cur FOR qry;
LOOP
FETCH cur INTO result;
EXIT WHEN cur%NOTFOUND;
IF filaFinal IS NULL THEN
filaFinal := resul;
ELSE
filaFinal := filaFinal ',' result;
END IF;
END LOOP;
RETURN filaFinal;
END;
/

Ejemplo

SQL> create table prueba (nombre varchar2(30));

Table created.

SQL> insert into prueba values(‘Luis’);

1 row created.

SQL> insert into prueba values(‘Bruno’);

1 row created.

SQL> insert into prueba values(‘Matias’);

1 row created.

SQL> insert into prueba values(‘Gonzalo’);

1 row created.

SQL> commit;

1 row created.

SQL> select concatfilas('SELECT nombre FROM prueba') as nombres
2 FROM dual;


NOMBRES
------------------------------------------------------------------
Luis, Bruno, Matias, Gonzalo


Espero les haya servido

Saludos!
Gondalf.

miércoles, 9 de junio de 2010

Perdida de un Control File

Lo que primero tenemos que tener en claro que la pérdida de un control file multiplexado inmediatamente realiza un abort a la instancia. Como nosotros tenemos multiplexado nuestro control file (de no tenerlo, hacerlo!), realizar una recuperación de la instancia no es nada complicado.

Para el siguiente ejemplo supongamos que tenemos 3 control files:
/u02/oradata/test/control01.ctl
/u03/oradata/test/control02.ctl
/u04/oradata/test/control03.ctl

Por un fallo en el /u04 perdemos el control03.ctl, por ende la instancia cae dada esta perdida.
Para poder hacer el recover de la instancia lo que hacemos es modificar el parámetro CONTROL_FILES dentro del SPFILE suprimiendo el control03.ctl.

Los pasos a seguir son:

- Levantamos la base en NOMOUNT, lo hacemos en este modo dado que en MOUNT la base ya realiza un chequeo de los control files.

SQL> startup nomount
ORACLE instance started.
Total System Global Area     188743680 bytes
Fixed Size     778036 bytes
Variable Size     162537676 bytes
Database Buffers     25165824 bytes
Redo Buffers     262144 bytes


- Con la instancia en NOMOUNT podemos modificar el paramentro CONTROL_FILE dentro del spfile:

SQL> alter system set control_files =
2 '/u02/oradata/test/control01.ctl',
3 '/u03/oradata/test/control02.ctl'
4 scope = spfile;

System altered.

- Bajamos la instancia

SQL> shutdown immediate

ORA-01507: database not mounted
ORACLE instance shut down.


- Levantamos la instancia con el nuevo parametro aplicado

SQL> startup
ORACLE instance started.
Total System Global Area       188743680 bytes
Fixed Size       778036 bytes
Variable Size       162537676 bytes
Database Buffers       25165824 bytes
Redo Buffers       262144 bytes
Database mounted.
Database opened.


- Por último lo que podemos hacer es checkear que el parametro haya quedado correcto para lo cual hacemos la siguiente consulta

SQL> select name, value
2 from v$spparameter
3 where name = 'control_files';

NAME VALUE
--------------- --------------------------------------
control_files /u02/oradata/test/control01.ctl
control_files /u03/oradata/test/control02.ctl



Espero les haya servido

Saludos!
Gondalf

domingo, 30 de mayo de 2010

Renombrar un “Log Member”

Para poder renombrar un redo log member lo que necesitamos en primer lugar es el nuevo archivo de redo ya que el comando de SQL lo que hace únicamente es cambiar el puntero interno en el control file hacia el nuevo archivo de redo, es decir que el comando de SQL no modifica el archivo del sistema operativo.

Entonces, para poder renombrar el archivo de redo vamos a realizar los siguientes pasos:

1. Realizamos un shutdown de la base
SQL> shutdown immediate;


2. Copiamos o renombramos el archivo de redo utilizando comandos del sistema operativo


3. Montamos la base de datos

SQL> startup mount;


4. Realizamos el cambio en el puntero del archivo de control.

SQL> ALTER DATABASE RENAME FILE ‘old_redo_file’ TO              ‘new_redo_file’;


5. Abrimos la base de datos

SQL> ALTER DATABASE OPEN;


6. Por último realizamos un backup del archive de control ya que realizamos un cambio en el.


Espero les haya servido

Saludos!
Gondalf

miércoles, 19 de mayo de 2010

Cambiando el orden de las columnas

Como alguno de ustedes ya sabrá el proceso de cambiar el orden las columnas de una tabla en Oracle no se realiza con un simple ALTER TABLE.

Para poder llevar a cabo esta tarea a continuación vamos a ver una sucesión de pasos que nos van a ayudar a solucionar nuestra necesidad.

Cabe aclarar que si la tabla tiene indices asociados primero habría que relevarlos dado que los vamos a perder con este procedimiento.

SQL> create table EJEMPLO (col1 number, col2 number, col3 number);

Table created.

SQL> desc EJEMPLO;
Name          Null?     Type
---------- ------ ----------------
COL1 NUMBER
COL2 NUMBER
COL3 NUMBER

SQL> create table AUXILIAR as select col3, col2, col1 from EJEMPLO;

Table created.

SQL> drop table EJEMPLO;

Table dropped.

SQL> alter table AUXILIAR rename to EJEMPLO;

Table altered.

SQL> desc EJEMPLO;
Name          Null?     Type
---------- ------ ----------------
COL3 NUMBER
COL2 NUMBER
COL1 NUMBER

Espero les haya servido.

Saludos!
Gondalf

lunes, 10 de mayo de 2010

Agregar un disco a un diskgroup en ASM

La idea de este post es mostrarles un poco como podemos agregar espacio (un disco) a nuestro ASM, primero vamos
a crear el link necesario a nuestro raw device para que ASM pueda "verlo", para realizar esto hacemos lo siguiente:

1- Nos paramos en el directorio donde tenemos creados los links a los raw devices

TEST:/u00/oradata/asm# ls -latr
total 2
lrwxr-xr-x 1 oracle oinstall 17 May 15 2009 asm_disk_01 -> /dev/rdisk/disk61
lrwxr-xr-x 1 oracle oinstall 17 May 15 2009 asm_disk_02 -> /dev/rdisk/disk68
lrwxr-xr-x 1 oracle oinstall 17 May 15 2009 asm_disk_03 -> /dev/rdisk/disk73
lrwxr-xr-x 1 oracle oinstall 17 May 15 2009 asm_disk_04 -> /dev/rdisk/disk81
lrwxr-xr-x 1 oracle oinstall 17 May 15 2009 asm_disk_05 -> /dev/rdisk/disk86
drwxrwxr-x 2 oracle dba 1024 May 15 2009 .
drwxrwxr-x 4 oracle dba 96 May 7 15:22 ..
2- Una vez que el sys admin nos indica que raw tenemos presentado vamos a proceder a darle los permisos necesarios
(en este ejemplo será el disk78)

TEST:/u00/oradata/asm# chown oracle:dba /dev/rdisk/disk78

3- Generamos el link necesario con el comando de UNIX ln -s

TEST:/u00/oradata/asm# ln -s /dev/rdisk/disk78 /u00/oradata/asm/asm_disk_06

4- Revisamos nuestro nuevo link

TEST:/u00/oradata/asm# ll
total 0
lrwxr-xr-x 1 oracle oinstall 17 May 15 2009 asm_disk_01 -> /dev/rdisk/disk61
lrwxr-xr-x 1 oracle oinstall 17 May 15 2009 asm_disk_02 -> /dev/rdisk/disk68
lrwxr-xr-x 1 oracle oinstall 17 May 15 2009 asm_disk_03 -> /dev/rdisk/disk73
lrwxr-xr-x 1 oracle oinstall 17 May 15 2009 asm_disk_04 -> /dev/rdisk/disk81
lrwxr-xr-x 1 oracle oinstall 17 May 15 2009 asm_disk_05 -> /dev/rdisk/disk86
lrwxr-xr-x 1 root sys 17 May 7 16:12 asm_disk_06 -> /dev/rdisk/disk78
5- Como vemos el link lo creamos con un usuario y un grupo erróneo, por lo que debemos cambiarlo, para eso ejecutamos lo siguiente

TEST:/u00/oradata/asm# chown -h oracle:oinstall asm_disk_06

6- Volvemos a chequear

TEST:/u00/oradata/asm# ll
total 0
lrwxr-xr-x 1 oracle oinstall 17 May 15 2009 asm_disk_01 -> /dev/rdisk/disk61
lrwxr-xr-x 1 oracle oinstall 17 May 15 2009 asm_disk_02 -> /dev/rdisk/disk68
lrwxr-xr-x 1 oracle oinstall 17 May 15 2009 asm_disk_03 -> /dev/rdisk/disk73
lrwxr-xr-x 1 oracle oinstall 17 May 15 2009 asm_disk_04 -> /dev/rdisk/disk81
lrwxr-xr-x 1 oracle oinstall 17 May 15 2009 asm_disk_05 -> /dev/rdisk/disk86
lrwxr-xr-x 1 oracle oinstall 17 May 7 16:12 asm_disk_06 -> /dev/rdisk/disk78
7- Por otro lado chequemos que el raw presentado tenga los permisos necesario para que ASM lo pueda acceder correctamente

TEST:/u00/oradata/asm# ls -latr /dev/rdisk/disk78
crw-r-----   1 oracle     dba         23 0x000014 May 15  2009 /dev/rdisk/disk78
/*********************************************/

Una vez terminado el trabajo de generar el link para ASM estamos en condiciones de agregar el disco a nuestro diskgroup.
Quiero aclarar que voy a seguir los pasos que aconseja Oracle para agregar un nuevo disco a un diskgroup existente (Metalink ID 557348.1)

Paso 1 - Creamos un nuevo diskgroup para testear si ASM puede acceder al nuevo disco y asi no correr riesgos con nuestro diskgroup productivo
SQL> CREATE DISKGROUP TEST EXTERNAL REDUNDANCY DISK 'YOUR DISK';

Paso 2 - Checkeamos si el diskgroup esta creado y montado
SQL> SELECT STATE, NAME FROM V$ASM_DISKGROUP;

Paso 3 - Si tenemos varias instancias de ASM (hablamos de un RAC sobre ASM) debemos montar el diskgroup en las demas instancias de ASM
SQL> ALTER DISKGROUP TEST MOUNT;

Paso 4 - Chequeamos en todas las demás instancias de ASM si el diskgroup está montado
SQL> SELECT STATE, NAME FROM V$ASM_DISKGROUP;

Paso 5 - Desmontamos el diskgroup de todas las instancias menos de una, es de esta última de donde eliminamos la instancia de ASM
SQL> alter diskgroup test dismount; --(desde todas las instancias de ASM salvo de una).

SQL> DROP DISKGROUP TEST; --(desde la instancia ASM de donde no desmontamos el diskgroup).

Paso 6 - Agregamos el nuevo disco a nuestro diskgroup existente
SQL> ALTER DISKGROUP ADD DISK 'YOUR DISK';

Espero les haya servido.

Saludos!
Gondalf

viernes, 7 de mayo de 2010

Scripts sobre tamaños en general

•• Conocer Tamaño ocupado por una tabla concreta incluyendo los índices de la misma

SELECT sum(bytes)/1024/1024 Mb
FROM user_segments
WHERE segment_type in ('TABLE','INDEX') and (segment_name='NOMBRETABLA' or segment_name in
(SELECT index_name FROM user_indexes WHERE table_name='NOMBRETABLA'));

•• Conocer Tamaño ocupado por una columna de una tabla

SELECT sum(vsize('NOMBRECOLUMNA'))/1024/1024 Mb FROM 'NOMBRETABLA';

•• Conocer Espacio ocupado por cada usuarios

SELECT owner, SUM(BYTES)/1024/1024 FROM dba_extents
GROUP BY owner;

•• Conocer Espacio ocupado por los diferentes segmentos (tablas, índices, undo, rollback, cluster, ...)

SELECT SEGMENT_TYPE, SUM(BYTES)/1024/1024 FROM dba_extents
GROUP BY SEGMENT_TYPE;

•• Conocer el tamaño ocupado por una tabla

SELECT SEGMENT_name, SUM(BYTES)/1024/1024 FROM dba_extents
WHERE segment_name = 'NOMBRETABLA'
GROUP BY segment_name;

•• Conocer el espacio ocupado por todos los objetos de la base de datos, muestra los objetos que más ocupan primero

SELECT segment_name, sum(bytes)/1024/1024 FROM dba_extents
GROUP BY segment_name
ORDER BY 2 desc;

•• Conocer el espacio ocupado por la base de datos

SELECT sum(bytes)/1024/1024 FROM dba_extents;


Espero les haya servido

Saludos!
Gondalf

jueves, 22 de abril de 2010

Tablespace Temporal

Seguramente alguna vez necesiten recrear el tablespace temporal que tiene la base por default. Porque?
Una posible explicación podría ser que nuestro tablespace temporal está configurado en autoextent y por alguna razón aumentó considerablemente su tamaño y no podemos realizarle un RESIZE ya que nos devuelve el siguiente error:

SQL> alter database tempfile
2 '/u01/oradata/PRUEBA/temp01.dbf'
3 resize 100M;

alter database tempfile '/u01/oradata/PRUEBA/temporal01.dbf' resize 100M
*
ERROR at line 1:
ORA-03297: file contains used data beyond requested RESIZE value


Si esto ocurre debemos recurrir a otra estrategia. Tenemos 2 opciones las cuales vamos a tratar de explicar:

OPCION 1

Lo que vamos a hacer es borrar el tablespace y volverlo a crear, pero dado que no podemos borrar el tablespace temporal que la base tiene asignado por default debemos crear uno “provisorio”, creo que se va a entender mejor si vemos los pasos que necesitamos realizar:

SQL> create temporary tablespace temp tempfile
2 '/u01/oradata/PRUEBA/temp01.dbf'
3 size 100M;

Tablespace created.

SQL> alter database default temporary
2 tablespace temp1;

Database altered.

SQL> drop tablespace TEMPORAL including contents and datafiles;

Tablespace dropped.

SQL> create temporary tablespace TEMPORAL
2 tempfile '/u01/oradata/PRUEBA/temporal01.dbf' size 100M
3 autoextend on next 100M maxsize 32767M;


Tablespace created.

SQL> alter database default temporary tablespace temporal;

Database altered.

SQL> drop tablespace temp1 including contents and datafiles;

Tablespace dropped.

OPCION 2

Existe otro método que podemos usar en Oracle 10g (lo podemos usar a partir de 9i) que nos permite borrar el tempfile directamente sin eliminar el tablespace, esto debemos hacerlo sin usuarios trabajando o trabajos batch ejecutándose que usen el temporal.
Para obtener el nombre del tempfile a borrar podemos hacer lo siguiente:

SQL> SELECT tablespace_name, file_name
2 FROM dba_temp_files
3 WHERE tablespace_name = 'TEMPORAL';
TABLESPACE_NAME    FILE_NAME                            
----------------- --------------------------------
TEMPORAL /u01/oradata/PRUEBA/temporal01.dbf
Teniendo el nombre podemos proceder a borrarlo, para eso ejecutamos lo siguiente:

SQL> alter database tempfile
2 '/u01/oradata/PRUEBA/temporal01.dbf'
3 drop including datafiles;

Database altered.

SQL> alter tablespace TEMPORAL add tempfile
2 '/u01/oradata/PRUEBA/temporal01.dbf' size 512m
3 autoextend on next 250m maxsize unlimited;


Tablespace altered.

SQL> SELECT tablespace_name, file_name, bytes
2 FROM dba_temp_files
3 WHERE tablespace_name = 'TEMPORAL';
TABLESPACE_NAME   FILE_NAME                   
----------------- --------------------------------
TEMPORAL /u01/oradata/TESTDB/temporal01.dbf
Espero les haya servido

Saludos!
Gondalf

martes, 13 de abril de 2010

Investigando un poquito: RECYCLEBIN

Este es uno de los nuevos “features” que Oracle tiene en su versión 10g. Como su nombre lo indica su función es similar al de una papelera de reciclaje, es decir que si borramos una tabla la misma irá a parar a esa “papelera”, gracias a esto podremos recuperar la tabla borrada.

Por default este feature esta activo en Oracle, el parámetro que podemos chequear para verlo es RECYCLEBIN, el cual podremos modificar a nivel de sesión o de sistema.

Entonces, como mencionamos si tenemos el parámetro en ON, si borramos tablas estas no desaparecerán por completo sino que Oracle las renombrara junto con los objetos asociados (triggers, índices, ets.), y ese nombre empezará con el prefijo BIN$.

Disponemos de dos vistas para ver el contenido de la papelera de Oracle:

- USER_RECYCLEBIN (su sinónimo es recyclebin)
- DBA_RECYCLEBIN


Para aclarar un poquito más esto, veamos un ejemplo:

SQL> create table PRUEBA (col1 number, col2 number);

Table created

SQL> drop table PRUEBA;

Table dropped

SQL> select object_name, original_name, can_undrop “und”,
2 droptime from dba_recyclebin;
OBJECT_NAME                     ORIGINAL_NAME  UND    DROPTIME
------------------------------ ------------- ------ -------------------
BIN$gDFsgStAQBPgRAAiZDYAkw==$0 PRUEBA YES 2010-04-05:16:10:12
Como podemos ver, borramos la tabla pero aun la seguimos teniendo en la papelera, de hecho si quisiéramos podríamos un select al objeto “BIN$gDFsgStAQBPgRAAiZDYAkw==$0”, lo cual nos traería la información que guardaba la tabla PRUEBA

Para poder recuperar la tabla debemos hacer lo siguiente:

SQL> flashback table PRUEBA to before drop;

Con esto tenemos la tabla PRUEBA nuevamente en nuestra base de datos como estaba antes de ser borrada.

Una cosa que nos tiene que quedar claro que cuando borramos una tabla, como vimos, esta no se borra, sino que solo se “renombra” quedando en la papelera de reciclaje. Esto quiere decir que seguimos teniendo el espacio ocupado por dicha tabla. Para borrarla definitivamente debemos “purgar” la papelera de reciclaje, para realizar esta tarea ejecutamos lo siguiente:

SQL> purge table “BIN$gDFsgStAQBPgRAAiZDYAkw==$0”;

Table purged

SQL> select * from recyclebin;

No row selected

Por otro lado, como sabemos, si borramos una tabla oracle la renombra con el prefijo BIN$ y una serie de caracteres, en otro momento volvemos a crear dicha tabla y la volvemos a eliminar, es decir que vamos a tener 2 versiones de la tabla dentro de la “papelera”. Si queremos recuperar la tabla, Oracle siempre nos recuperará la versión más reciente que tenga de la misma en la papelera.
Si queremos recuperar otra versión que no sea la última de una tabla debemos hacer un flashback table pero con el nombre del objeto, es decir “BIN$.....”, ejemplo:

SQL> flashback table “BIN$gDFsgStAQBPgRAAiZDYAkw==$0”
2 to before drop;


OBJETOS ASOCIADOS A UNA TABLA

Qué pasaría si borramos una tabla que contiene un índice o un trigger?
Veamos una serie de pasos que nos muestran el comportamiento que tiene Oracle al respecto:

SQL> create table PRUEBA (col1 number, col2 number);

Table created

SQL> create index IX_PRUEBA on PRUEBA(col2);

Index created

SQL> drop table PRUEBA;

Table dropped

SQL> select object_name, original_name, can_undrop “und”,
2 droptime from recyclebin;

OBJECT_NAME                     ORIGINAL_NAME  UND     DROPTIME
--------------- ------------- ------ -------------------
BIN$hAur4QSAPDbgRAARhV9U+A==$0 IX_PRUEBA NO 2010-04-12:12:19:30
BIN$hAur4QSBPDbgRAARhV9U+A==$0 PRUEBA YES 2010-04-12:12:19:30

Como podemos ver el campo can_undrop referido al índice tiene como valor ‘NO’, esto se debe a que el índice está asociado a la tabla y no le podremos hacer un restore al objeto por sí solo.

Cuando ejecutemos el flashback de la tabla veremos lo siguiente:

SQL> flashback table PRUEBA to before drop;

Flashback complete

SQL> select index_name from user_indexes
2 where table_name = ‘PRUEBA’;

INDEX_NAME
------------------------------
BIN$hAur4QSAPDbgRAARhV9U+A==$0


Como podemos notar Oracle trajo nuevamente la tabla a su schema original, lo hizo junto con su indice pero con la salvedad que el índice no volvió con el nombre anterior ya que Oracle por alguna razón no ‘recrea’ los índices con el mismo nombre que tenían anteriormente sino con el nombre que obtuvieron en la papelera de reciclaje.
Si querés traer la tabla sin su índice lo que se puede hacer es un purge del índice mientras estén en la papelera para luego hacer un flaskback de la tabla.


DESHABILITAR LA PAPELERA DE RECICLAJE

Existen 2 maneras de que al borrar una tabla no vaya a parar a la papelera de reciclaje, el primero es agregando al final de una sentencia ‘DROP TABLE’ la palabra PURGE, con esto nos aseguramos que la tabla se elimine completamente, ejemplo

SQL> create table PRUEBA (col1 number, col2 number);

Table created

SQL> drop table PRUEBA purge;

Table dropped

SQL> select object_name, original_name, can_undrop “und”,
2 droptime from recyclebin;

No rows selected

La otra manera de evitar que vayan las tablas a la papelera cuando las borramos es desactivar directamente a nivel de sesión la papelera de reciclaje, esto lo hacemos de la siguiente manera

SQL> alter session set recyclebin=off;

Session altered

Espero les haya servido

Saludos!
Gondalf.

miércoles, 31 de marzo de 2010

Como copiar/clonar de forma rápida un base de datos?

La tarea de clonación de de una base de datos es algo bastante frecuente para un DBA ya que muchas veces es necesario tener ambientes de desarrollo o testeo actualizados con los datos que tenemos en ambientes productivos. Por lo tanto y al ser algo frecuente sería bueno contar con un procedimiento rápido y fácil para llevarlo a cabo.

Para realizar dicho procedimiento vamos a realizar una serie de pasos que detallo a continuación:

1- En nuestra base origen (a partir de ahora PROD) nos conectamos al SQL*Plus y ejecutamos:

SQL> ALTER DATABASE BACKUP CONTROLFILE TO TRACE;

Con esta sentencia obtenemos la sintaxis para realizar el “CREATE CONTROLFILE” (este archivo lo podemos encontrar dentro del directorio de trace, user_dump_dest). El archivo cuenta con la siguiente forma:

STARTUP NOMOUNT
CREATE CONTROLFILE REUSE DATABASE "PROD" NORESETLOGS
NOARCHIVELOG
MAXLOGFILES 12
MAXLOGMEMBERS 2
MAXDATAFILES 280
MAXINSTANCES 1
MAXLOGHISTORY 120
LOGFILE
GROUP 1 ('/u01/oradata/PROD/log1a.dbf',
'/u01/oradata/PROD/log1b.dbf') SIZE 50M,
GROUP 2 ('/u01/oradata/PROD/log2a.dbf',
'/u04/oradata/PROD/log2b.dbf') SIZE 50M
DATAFILE
'/u01/oradata/PROD/system01.dbf',
'/u01/oradata/PROD/prueba.dbf'
;
# Recovery is required if any of the datafiles are restored
# backups, or if the last shutdown was not normal or immediate.
RECOVER DATABASE
# Database can now be opened normally.
ALTER DATABASE OPEN;


2- Realizamos un shutdown en la base PROD

SQL> SHUTDOWN IMMEDIATE;

3- Ahora es momento de copiar todos los ‘data files’ y ‘log files’ al nuevo server o a la nueva ubicación. Si cambiamos el nombre de los ‘data files’ debemos realizar también los cambios en el controlfile. A modo de ejemplo supongamos que tenemos todos los ‘data files’ dentro de /u01/oradata/PROD/ y los vamos a llevar al servidor TESTER en la ubicación /u01/oradata/TEST/

rcp /u01/oradata/PROD/* TESTER:/u01/oradata/TEST

4- Copiar el archivo que obtuvimos en el punto 1 (de ahora en adelante lo llamaremos clona.sql) y modificar la siguiente línea

CREATE CONTROLFILE REUSE DATABASE "PROD" NORESETLOGS

Por la siguiente línea

CREATE CONTROLFILE SET DATABASE "TEST" RESETLOGS

5- Quitar las siguientes líneas de clona.sql:

- RECOVER DATABASE

- ALTER DATABASE OPEN


6- Siguiendo con los cambios en clona.sql, es el turno de modificar el directorio de los ‘data files’ y ‘log files’, a modo de ejemplo:

'/u01/oradata/PROD/system01.dbf'
'/u01/oradata/PROD/prueba.dbf'


Por las siguientes línea

'/u01/oradata/TEST/system01.dbf'
'/u01/oradata/TEST/prueba.dbf'


7- En este paso podríamos crear los directorios necesarios para los ´dump´ de Oracle, a modo de ejemplo:

TEST@TESTER ] cd $ORACLE_BASE/admin
TEST@TESTER ] mkdir TEST
TEST@TESTER ] cd TEST
TEST@TESTER ] mkdir bdump
TEST@TESTER ] mkdir cdump
TEST@TESTER ] mkdir udump
TEST@TESTER ] mkdir pfile


8- Copiar el archivo de parámetro (pfile.ora), a modo de ejemplo

cd $ORACLE_BASE/admin/PROD/pfile/
rcp *.ora TESTER:/u01/oracle/admin/TEST/pfile


9- Corremos desde el sqlplus en TESTER el archivo clona.sql

SQL> @db_create_controlfile.sql

10- Luego deberíamos abrir la base de datos.

Espero que les haya servido

Saludos!
Gondalf

jueves, 25 de marzo de 2010

Consultas a la DBA_VIEWS

Como muchos saben, realizar una consulta a la vista dba_views para buscar un texto en particular que posea una vista no es una tarea sencilla. Esto se debe a que el campo TEXT de la vista es de tipo LONG por lo que no podemos hacer una comparación en la clausula where ya que nos arrojaría el siguiente error:

SQL> select * from dba_views where text like '%PRUEBA%'

ORA-00932: inconsistent datatypes: expected NUMBER got LONG

Para resolver este problema a continuación vamos a ver dos posibles soluciones:

1- La primera es a través de un script con el cual vamos a poder ver las vistas que contengan el texto que necesitemos buscar

BEGIN
FOR r IN (SELECT owner, view_name, text FROM dba_views) LOOP
IF r.text LIKE '%PRUEBA%' THEN
dbms_output.put_line(r.view_name);
END IF;
END LOOP;
END;
/


En este caso con la creación de un cursor podemos realizar la búsqueda que necesitamos del campo TEXT.

2- La segunda alternativa es copiar los datos a una tabla “temporal”, convirtiendo los datos LONG en CLOBs, para esto podemos hacer lo siguiente:

SQL> create table my_dba_views (owner, view_name, text) as select owner, view_name, to_lob(text) from dba_views;

Table created

Ahora podemos realizar la consulta normalmente

SQL> select view_name from my_dba_views where upper(text) like '%PRUEBA%';


Espero les haya servido

Saludos!
Gondalf

domingo, 21 de marzo de 2010

Usando SRVCTL

La herramienta srvctl es la que Oracle nos recomienda que utilicemos para poder interactuar con el CRS y con la registry del cluster. Esta herramienta podemos decir que está muy bien documentada y es bastante amigable para utilizar.
Si utilizamos otras herramientas que no están soportadas por Oracle corremos el riesgo de que se dañe el archivo OCR.

El formato básico para de este comando es el siguiente

srvctl <'command'> <'target'> [options]

- En donde [options] puede ser cualquiera de la siguiente lista:

enable|disable|start|stop|relocate|status|add|remove|modify|getenv|setenv|
unsetenv|config


- Y donde <'target'> puede ser o bien una base de datos, una instancia, un servicio, una instancia de ASM o bien "nodeapps" Aplicaciones del nodo por darle una traducción, estas son los siguientes procesos: la VIP, ONS, GSD, y el listener junto a las aplicaciones definidas dentro del cluster de Oracle)

En la siguiente tabla tenemos un resumen de los posibles comandos a ejecutar con SRVCTL:


Como podemos ver, son muchas las sentencias a recordar, y quizá sea una tarea un poco difícil el recordar todas, por lo que para facilitarnos esa tarea tenemos:

- srvctl –help tiene la siguiente salida

Usage: srvctl <'command'> <'object'> [<'options'>]
command: enable|disable|start|stop|relocate|status|add|remove|modify|getenv|setenv|unsetenv|config
objects: database|instance|service|nodeapps|asm|listener
For detailed help on each command and object and its options use:
srvctl <'command'> <'object'> -h
-

srvctl –h muestra la información anterior pero con mayor detalle.

ALGUNOS EJEMPLOS

- Levantar la instancia PRUEBA1 de la base PRUEBA.

[oracle@Testeo1 oracle]$ srvctl start instance -d PRUEBA -i PRUEBA1

- Bajamos la base PRUEBA: para esto bajamos todas sus instancias y sus servicios en todos los nodos.

[oracle@Testeo1 oracle]$ srvctl stop database -d PRUEBA

- Bajamos el “nodeapps” en el nodo Testeo1

[oracle@Testeo1 oracle]$ srvctl stop nodeapps -n Testeo1

- Agregar una nueva instancia a la base PRUEBA, en este caso PRUEBA3, la cual está corriendo en el nodo Testeo1.

[oracle@Testeo1 oracle]$ srvctl add instance -d PRUEBA -i PRUEBA3 -n Testeo1

- Cambiar la VIP (IP virtual) en uno de los nodos del RAC

[oracle@Testeo1 oracle]$ srvctl modify nodeapps -A new_address

- Deshabilitamos la instancia de ASM sobre Testeo1.

[oracle@Testeo1 oracle]$ srvctl disable asm -n Testeo1

Espero que les haya servido.

Saludos!
Gondalf

sábado, 13 de marzo de 2010

Indices Virtuales

Vamos a intentar explicar un poco que son y para sirven los índices virtuales en Oracle.

El propósito de este tipo de índices es el hecho de simular la existencia de uno real, pero sin la necesidad de su construcción, nos ayudaran a determinar utilizando CBO (evaluación del plan de ejecución basada en costos) si es bueno o no su creación “física”. Su definición se encuentra en el diccionario de datos (en ciertas vistas) pero si realizamos una consulta en la vista DBA_SEGMENTS no lo encontraremos.

Oracle posee una cláusula oculta mediante la cual nos permitirá crear este tipo de índices, la misma es “nosegment”.
Además de conocer esta clausula debemos tener en cuenta que para poder utilizarlos es necesario setear el parámetro oculto “_use_nosegment_indexes”

La creación de los mismos se realiza de la siguiente manera:

SQL> CREATE unique INDEX VIRTUAL_PRUEBA on table_name(col_name) NOSEGMENT;

Y para utilizarlo, como dijimos seteamos la siguiente variable:

SQL> ALTER SESSION SET "_use_nosegment_indexes" = TRUE;

Veamos como buscamos el índice que creamos en las vistas del diccionario de datos:

SQL> select segment_name, segment_type, bytes
2 from dba_segments
3 where segment_name = 'VIRTUAL_PRUEBA';


no rows selected

SQL> select object_name, object_type, status
2 from dba_objects
3 where object_name = 'VIRTUAL_PRUEBA;


OBJECT_NAME |OBJECT_TYPE |STATUS
------------------|-----------------|---------------
VIRTUAL_PRUEBA |INDEX |VALID

SQL> select index_name, index_type, status
2 from dba_indexes
3 where index_name = 'VIRTUAL_PRUEBA';


INDEX_NAME |INDEX_TYPE |STATUS
------------------------------|------------|---------------
VIRTUAL_PRUEBA |NORMAL |VALID

Por último, quería mostrar algunas tareas que podemos hacer o no con los índices virtuales:

1- Alterarlos

SQL> alter index VIRTUAL_PRUEBA rebuild;

ERROR at line 1:
ORA-08114: can not alter a fake index

SQL> alter index VIRTUAL_PRUEBA storage(pctincrease 0);

ERROR at line 1:
ORA-08114: can not alter a fake index

2- Intentar transformarlos en índices reales

SQL> create index VIRTUAL_PRUEBA on table_name(col1);

ERROR at line 1:
ORA-00955: name is already used by an existing object

Esto ocurre dado que los índices virtuales generan entradas en algunas tablas del diccionario de datos.
La solución en estos casos es eliminar el índice virtual, y crear el físico

SQL> drop index VIRTUAL_PRUEBA;

Index dropped.

SQL> create index VIRTUAL_PRUEBA on am301(col1);

Index created.

Siguiendo con el tema, lo que si podemos hacer es crear un índice virtual afectando a ciertas columnas de una tabla y por otro lado crear un índice físico (con otro nombre) pero que también afecte a las mismas columnas.

SQL> create index VIRTUAL on emp(col1, col2, col3) nosegment;

Index created.

SQL> create index FISICO on emp(col1, col2, col3);

Index created.

Una vez que terminaron de trabajar con estos índices se recomienda eliminarlos.

Espero que les haya servido.

Saludos!
Gondalf

martes, 9 de marzo de 2010

Borrando una base de datos

Antes que nada, veamos un poco en qué consiste eliminar una base de datos.

Lo que debemos tener en cuenta para eliminar una base de datos los archivos que debemos borrar son:
- datafiles
- redo logs files
- control files
- archivos de parametría

Con la sentencia “drop database” (eso es posible desde la versión 10g de Oracle) eliminamos todos los ‘control files’ y todos los demás archivos listados en dicho archivo.

Ahora bien, para poder ejecutar un “drop database” debemos tener en cuenta lo siguiente:

- La base de datos debe estar cerrada y montada
- La base de datos debe estar montada en modo ‘exclusivo’
- La base de datos debe estar montada en forma ‘restricted’

Para eso, realizamos lo siguiente:

1. Bajamos la base de datos
SQL> shutdown immediate;

2. Montamos la base en modo exclusivo y ‘restricted’
SQL> startup mount exclusive restrict;

3. Por último procedemos a eliminar la base
SQL> drop database;

Cabe aclarar que ‘drop database ’ no elimina los ‘archive logs’ y tampoco tiene efecto sobre copias o backups de la base de datos. Lo mejor para eliminar esos archivos es usar RMAN.

Por último, y quizá la forma más fácil de llevar a cabo el borrado de la base es utilizando ‘Database Configuration Assistant’, con el que podemos eliminar la base y remover los archivos.

Espero les haya servido.

Saludos!
Gondalf.

viernes, 5 de marzo de 2010

FROMUSER TOUSER en DataPump

Para poder usar DataPump debemos crear un “directory object” y otorgar los privilegios necesarios al usuario para que pueda trabajar con ese directorio.
Para crear dicho directorio debemos ejecutar:

SQL> CREATE DIRECTORY prueba_dpump AS ‘/u01/oracle/prueba’;

Una vez creado el directorio, tendremos que darles los permisos necesarios a los usuarios que queramos para que pueda escribir o leer sobre ese directorio. Para eso hacemos lo siguiente (Usamos al usuario Scott como ejemplo):

SQL> GRANT READ,WRITE ON DIRECTORY prueba_dpump TO scott;

A su vez, a nivel operativo oracle debe tener acceso de lectura y escritura sobre el directorio físico.

Una vez que tenemos todo lo anterior, podemos proceder a exportar el owner scott con el siguiente comando:

$ORACLE_HOME\bin\expdp ‘scott/password’ DIRECTORY=prueba_dpump dumpfile=scott.dmp

Habiendo realizado esta pequeña introducción para dataPump lo que quería compartir en este post es el cambio que hubo con dataPump cuando intentamos realizar un import en un owner distinto al que exportamos.

Antes, para realizar esta operación utilizábamos el siguiente comando (en este caso pasaremos las tablas del usuario scott al usuario peter):

$ORACLE_HOME\bin\imp ‘username/password’ FILE=scott.dmp FROMUSER=scott TOUSER=peter TABLES=(*)

Con data Pump Import ahora tenemos:

$ORACLE_HOME\bin\impdp ‘username/password’ DIRECTORY=prueba_dpump DUMPFILE=scott.dmp TABLES=scott.emp REMAP_SCHEMA=scott:jim

Como podemos ver la opción FROMUSER/TOUSER fue sustituida por la opción REMAP_SCHEMA

Espero les haya servido

Saludos!
Gondalf