miércoles, 18 de junio de 2008

High Water Mark (HWM)

Generalmente, cuando se crea una tabla o un índice... se crea un segmento asociado al objeto. El segmento se crea con determinados bloques del data file, pero muy poco espacio es destinado para nuestro uso. Cuando los datos van llenando los bloques asignados al segmento, se van alocando más bloques para que usemos. A medida que los bloques van siendo alocados, la HWM se posiciona en el último bloque para mostrarnos la cantidad total de bloques alocados hasta el momento y estaban disponibles para ser usados. Un error común es pensar que a medida que eliminamos datos de los bloques, la HWM se refresca para mostrarnos que estamos utilizando menos bloques; pero la realidad es que la HWM se mantiene siempre apuntando al último bloque alocado. Sabemos que cuando realizamos un Full Scan, son leídos secuencialmente todos los bloques de la tabla hasta la HWM, por lo cual, debemos tener en claro que aunque eliminemos datos de una tabla, ese espacio "vacío" se va a seguir leyendo, lo cual trae como consecuencia la lectura de bloques innecesarios.
Veamos un ejemplo:
SQL> CREATE TABLE emp
2 (id NUMBER , sexo VARCHAR2(1 )) ;

Table created.

SQL> INSERT INTO emp
2 SELECT level , 'M'
3 FROM dual
4 CONNECT BY level <= 800000 ; 800000 rows created. SQL> INSERT INTO emp
2 SELECT level , 'F'
3 FROM dual
4 CONNECT BY level <= 200000 ; 200000 rows created. SQL> commit;

Commit complete.

SQL> ANALYZE TABLE emp COMPUTE STATISTICS ;

Table analyzed.

SQL> SET AUTOTRACE TRACEONLY
SQL> SELECT sexo
2 FROM emp
3 WHERE id = 900000 ;

no rows selected


Execution Plan
----------------------------------------------------------
Plan hash value: 3956160932

--------------------------------------------------------------------------
Id Operation Name Rows Bytes Cost (%CPU) Time
--------------------------------------------------------------------------
0 SELECT STATEMENT 1 5 495 (10) 00:00:06
* 1 TABLE ACCESS FULL EMP 1 5 495 (10) 00:00:06
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter("ID"=900000)


Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
1655 consistent gets
0 physical reads
0 redo size
291 bytes sent via SQL*Net to client
384 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed

SQL>
SQL> DELETE FROM emp
2 WHERE sexo = 'M' ;

800000 rows deleted.

SQL> commit;

Commit complete.

SQL> SET AUTOTRACE TRACEONLY
SQL>
SQL> SELECT sexo
2 FROM emp
3 WHERE id = 900000 ;

no rows selected


Execution Plan
----------------------------------------------------------
Plan hash value: 3956160932

--------------------------------------------------------------------------
Id Operation Name Rows Bytes Cost (%CPU) Time
--------------------------------------------------------------------------
0 SELECT STATEMENT 1 5 495 (10) 00:00:06
* 1 TABLE ACCESS FULL EMP 1 5 495 (10) 00:00:06
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter("ID"=900000)


Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
1655 consistent gets
0 physical reads
0 redo size
291 bytes sent via SQL*Net to client
384 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed

Como pudimos ver, aunque hayamos eliminados datos de la tabla, seguimos leyendo la misma cantidad de bloques que antes
porque la HWM no se refrescó y sigue apuntando al último bloque alocado en el segmento.

Para solucionar éste problema, podemos realizar:

1) TRUNCATE ...
- Si la tabla esta vacia podemos hacer un TRUNCATE para resetear la HWM.
Sino, podemos hacer un export de los datos, luego truncar la tabla y realizar un import.

2) ALTER TABLE ... MOVE
- De ésta manera reorganizamos la tabla. Tener en cuenta que luego de ejecutar el ALTER, hay
que hacer un REBUILD de todos los índices de la tabla!

3) Dropear y recrear el objeto (export/import)

4) ALTER TABLE ... SHRINK SPACE SHRINK SPACE COMPACT
- Para 10g en adelante.

Apliquemos a nuestro ejemplo el punto 2...


SQL> ALTER TABLE emp MOVE ;

Table altered.

SQL> ANALYZE TABLE emp COMPUTE STATISTICS ;

Table analyzed.

SQL> SET AUTOTRACE TRACEONLY
SQL> SELECT sexo
2 FROM emp
3 WHERE id = 900000 ;

no rows selected


Execution Plan
----------------------------------------------------------
Plan hash value: 3956160932

--------------------------------------------------------------------------
Id Operation Name Rows Bytes Cost (%CPU) Time
--------------------------------------------------------------------------
0 SELECT STATEMENT 1 5 100 (9) 00:00:02
* 1 TABLE ACCESS FULL EMP 1 5 100 (9) 00:00:02
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter("ID"=900000)


Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
335 consistent gets
0 physical reads
0 redo size
291 bytes sent via SQL*Net to client
384 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed


Como vemos, la HWM se refresco y ahora estamos leyendo sólo los bloques que contienen nuestros datos.

Reubicar y Renombrar Redo Log Members

Para cambiar el nombre o cambiar de ubicación a los redo logs, se debe tener privilegio de sistema para alterar la base de datos ALTER DATABASE. Además, se necesita privilegios de sistema operativo para copiar los archivos a la ubicación deseada y privilegios para abrir y respaldar la base de datos.

Nota: Es recomendable que antes de reubicar tus redo logs, o hacer un cambio estructural a la base de datos la respaldescompletamente, ya que se podría tener algún problema en la operación a realizar.Después de renombrar o reubicar un set de redo log files debes inmediatamente respaldar los archivos de control de la base de datos.


A continuación se describe el scenario:

1: Los redolog files de este ejemplo están localizados sobre dos discos: disk01 y disk02
2: El primer grupo de redo logs consiste de los siguientes miembros: /disk01/logs/log101.log y /disk02/logs/log102.log, y el segundo grupo consiste de los miembros /disk01/logs/log201.log y /disk02/logs/log202.log.
3: Los redolog files localizados sobre el disk01 deben ser reubicados al disk03, y deberán reflejar las siguientes rutas: /disk03/logs/log103.log y /disk03/logs/log203.log

Pasos para renombrar o reubicar los redo logs:

1: Bajar la base de datos:
SHUTDOWN

2: Copiar los redo redo log files a la nueva localización utilizando comandos de sistema operativo.

3: En el caso de Unix o Linux para mover los redo logs a una nueva localización ejecutamos el siguiente comando:
mv /disk01/logs/log101.log /disk03/logs/log103.logmv /disk01/logs/log201.log /disk03/logs/log203.log

4: Levantamos la base de datos en modo MOUNT:
STARTUP MOUNT

5: Utilizando la sentencia ALTER DATABASE con la cláusula RENAME FILE renombramos los redo logs:
ALTER DATABASERENAME FILE ‘/disk01/logs/log1a.log’, ‘/disk01/logs/log2a.log’ TO ‘/disk03/logs/log1c.log’, ‘/disk03/logs/log2c.log’;

6: Abrimos la base de datos:
ALTER DATABASE OPEN;

¿Como multiplexar un controlfile, utilizando OMF y ASM

Un problema con el que nos hemos encontrado en nuestro entorno de bases de datos, en concreto después de una instalación Oracle 10.2.0.1 parcheada a la 10.2.0.3, ha sido el de tener que duplicar el controlfile. En la siguiente nota indico el procedimiento que he seguido, teniendo en cuenta que se está haciendo uso de +ASM, usando la herramienta RMAN proporcionada por Oracle.

Lo primero que hay que hacer es identificar el controlfile existente:
SQL> SELECT NAME FROM V$CONTROLFILE;

Ahora hay que parar la base de datos e iniciarla en modo nomount:
SQL> SHUTDOWN IMMEDIATE;
….
SQL> STARTUP NOMOUNT;

Este es el momento de, usar RMAN para duplicar el archivo de control (la réplica se hará en el disco flash):

$ rman nocatalog;
RMAN> CONNECT TARGET;
RMAN> RESTORE CONTROLFILE TO ‘+DISCO_FLASH’ FROM ‘+DISCO_DATOS/ruta/nombre_ctl’;

Se identifica en este momento el nombre del controlfile en la flash; teniendo en cuenta que estamos haciendo uso de OMF, no sabemos qué nombre le va a poner Oracle al segundo controlfile, por eso es imprescindible este paso. Ésto se pude hacer desde SQLPLUS (como se puede observar más arriba) o con la nueva herramienta proporcionada por Oracle 10.2, ASMCMD:

$ asmcmd
ASMCMD> CD ‘+DISCO_FLASH’
ASMCMD> FIND -t controlfile*
Modificar ahora el SPFILE. Esto se puede hacer desde cualquier nodo cuando estamos en un entorno Oracle RAC:

SQL> ALTER SYSTEM SET CONTROL_FILES = ‘+DISCO_DATOS/ruta/nombre_ctl’,'+DISCO_FLASH/ruta/nombre_ctl’;

SQL> SHUTDOWN IMMEDIATE;
SQL> CONN / AS SYSDBA
SQL> STARTUP;

Reducir tablespace TEMP en ORACLE 10g

Crear el nuevo tablespace temporal de la base de datos, al que llamaremos TEMP2.

CREATE TEMPORARY TABLESPACE TEMP2 TEMPFILE SIZE 2048M AUTOEXTEND ON NEXT 128M MAXSIZE 4096M;

Obsérvese como en la creación de este tablespace se asigna un valor MAXISZE.

Configurar TEMP2 como tablespace temporal por defecto de la base de datos.


ALTER DATABASE DEFAULT TEMPORARY TABLESPACE TEMP2;

 Asegurarse que no existan sessiones utilizando el viejo tablespace Temporal

   a.  Buscar el numero de sesiones  desde V$SORT_USAGE: 
       SELECT USERNAME, SESSION_NUM, SESSION_ADDR FROM V$SORT_USAGE; 

   b.  Buscar el session ID from V$SESSION:

       Si los querys anterios devuelven resultados, entonces lo que haremos sera buscar el SID from the V$SESSION.

       SELECT SID, SERIAL#, STATUS FROM V$SESSION WHERE SERIAL#=SESSION_NUM;
       OR
       SELECT SID, SERIAL#, STATUS FROM V$SESSION WHERE SADDR=SESSION_ADDR; 

    c.  Kill Session:

    Ahora matamos la sesion con IMMEDIATE.

    ALTER SYSTEM KILL 'SID,SERIAL#' IMMEDIATE; 

Poner en estado OFFLINE el antiguo tablespace temporal. En este punto se observa que no se puede hacer:

ALTER TABLESPACE TEMP OFFLINE;

La bd devuelve el error ORA-03217.

Para solucionarlo, hay que actuar sobre los datafiles del tablespace. En este caso, uno:


ALTER DATABASE TEMPFILE ‘+disco/BD/tempfile/datafile’ OFFLINE

Borrar el antiguo tablespace temporal.

DROP TABLESPACE TEMP INCLUDING CONTENTS AND DATAFILES;

Comprobaremos ahora como los esquemas existentes en la base de datos tienen como tablespace temporal por defecto TEMP2 con la siguiente consulta:

select username,temporary_tablespace from dba_users;

Multiplexación de un controlfile en Oracle

Para multiplexar el control file seguimos unos pasos muy sencillos que te pueden sacar de varios aprietos.

Paso 1: Determinamos la ruta del controlfile utilizando el siguiente comando dentro de SQL*Plus:

show parameter control_files

o puedes utilizar la siguiente consulta:

select * from v$controlfile;

Paso 2: Alteramos el parámetro CONTROL_FILES para reflejar la ruta donde estará el nuevo control file:

alter system set control_files='/u01/oracle/oradata/control01.ctl','/u01/oracle/oradata/control02.ctl' scope=spfile;

En este caso el control01.ctl era el que ya teníamos trabajando en nuestra base de datos y el control02.ctl es el que aumentaremos para la multiplexación.

Paso 3: Una vez hecho este cambio procedemos a bajar la base de datos:

sqlplus / as sysdbashutdown immediate;


Paso 4: Con la base de datos abajo procedemos a multiplexar el controlfile en la nueva ruta:

cp /u01/oracle/oradata/control01.ctl /u01/oracle/oradata/control02.ctl

Paso 5: Levantamos nuevamente la base de datos:

sqlplus / as sysdbastartup;


Como pueden mirar la multiplexación del controlfile es un procedimiento que se realiza en frío por lo que habrá que programar mantenimiento de la base de datos para la realización de esta tarea.

Multiplexando los Redo Log Files en Oracle

El multiplexar es una opción que nos ayuda a reducir el riesgo de falla en la base de datos Oracle.

Para multiplexar los redo logs se debe proceder de la siguiente manera:

Paso 1: Realizamos un select a la siguiente vista para determinar la configuración actual de los redo logs de la base de datos:

SELECT * FROM V$LOGFILE;

Paso 2: Ejecutamos el comando ALTER DATABASE para generar miembros en cada grupo de redo logs:

ALTER DATABASE ADD LOGFILE MEMBER ‘/oracle/dbs/log2b.log’ TO GROUP 2;

Nota: Cuando adicionamos un miembro a un redo log group no es necesario especificar el tamaño, por consiguiente, todos los redo log files en el grupo serán del mismo tamaño.


Paso 3: Verificamos otra vez la vista V$LOGFILE para verificar que se ha añadido el nuevo miembro al grupo:

SELECT * FROM V$LOGFILE;

lunes, 16 de junio de 2008

¿Como habilitar la opción de Flashback Database sobre oracle 10g?

- Asegurarse de que la base de datos está en modo archive.
Esto se puede hacer con el comando:
SQL> archive log list;

- Configurar estos dos parámetros para el area de recovery:
db_recovery_file_dest db_recovery_file_dest_size

- Abrir la base de datos en MOUNT EXCLUSIVE y ejecutar la siguiente orden:
SQL> STARTUP MOUNT EXCLUSIVE;
SQL> ALTER DATABASE FLASHBACK ON;

- Configurar el parámetro que indica el tiempo de retención:
db_flashback_retention_target

- Chequear que realmente la opción de "Flashback Database" se habilitó correctamente:
SQL> select flashback_on
from v$database;
FLASHBACK_ON
------------------
YES

sábado, 14 de junio de 2008

¿Como cambiar el puerto http en Oracle XE?

Con esta breve explicación voy a mostrar como cambiar el puerto http por defecto a su instalación de Oracle XE.

Lo primero que debemos hacer es verificar en la base de datos el puerto http para lo cual se puede emplear la siguiente consulta:

SQL> select dbms_xdb.gethttpport from dual;

Una vez que se haya verificado el puerto http en cual se está trabajando se puede realizar el cambio con el siguiente procedimiento, en mi caso para cambiar al puerto 8585:

SQL> begin
dbms_xdb.sethttpport(’8585');
end;
/

Una vez ejecutado el procedimiento se podrá ingresar a la consola de Oracle XE con el nuevo puerto:

http://localhost:8585/apex