viernes, 6 de septiembre de 2013

Como mover el controlfile desde un filesystem hacia ASM

1. Identificar la ubicación el actual del controlfile

SQL> select name from v$controfile;

NAME
--------------------------------------------------------------------------------
/oradata/BASE/control01.ctl'


2. Parar la instancia y levantarla en nomount

SQL> shutdown normal
SQL> startup nomount

3. Usamos RMAN  para mover el controlfile hacia ASM

$ rman nocatalog
RMAN>connect target
RMAN>restore controlfile to '' from '';

Ej:

RMAN> restore controlfile to '+DGDATOS' from '/oradata/BASE/control01.ctl';

Starting restore at 06-SEP-13
allocated channel: ORA_DISK_1
channel ORA_DISK_1: sid=156 devtype=DISK

channel ORA_DISK_1: copied control file copy
Finished restore at 06-SEP-13



Nosotros solamente especificamos el nombre del diskgroup, oracle creará un OMF(Oracle Managed File). 
Usamos ASMCMD o sqlpus para identificar el nombre asignado al controlfile


4. En la instancia de ASM, identificamos el nombre del controlfile:

Usando ASMCMD:

$ asmcmd
ASMCMD> cd
ASMCMD> find -t controlfile . *

+DGDATOS/BASE/CONTROLFILE/current.308.577785757

ASMCMD>

5. Ahora del lado de la base de datos:

* Modificar el init.ora or spfile, reemplazando con el nuevo path para el init parámetro control_files.
* Si usamos init.ora, entonces modificamos el parámetro control_files y reiniciamos la instancia.
* Si usamos spfile, entonces

1) startup nomount the database instance
2) alter system set control_files='+DGDATOS/BASE/CONTROLFILE/current.308.577785757' scope=spfile;
3) shutdown immediate

6.
start the instance.

Verificar que el nuevo controlfile ah sido reconocido. 

NOTA : Los pasos 3 a 5 deberian ser repetidos para multiplexar el contolfile para en varios disgroup diskgroup .

miércoles, 19 de septiembre de 2012

Como clonar o duplicar una instancia oracle con la opción ACTIVE DATABASE de RMAN


Hola, luego de mucho tiempo de no publicar nada, aquí les traigo un procedimiento muy sencillo para hacer un clonado de nuestra base de datos de producción en un ambiente de test. La idea es utilizar RMAN y hacer el restore a través de la red, con lo cual esto es un beneficio cuando no disponemos de suficiente espacio en disco para alojar las piezas de backup de rman.

Nota: Antes de borrar el ambiente de test, salvaguardar todo lo que sea necesario, yo particularmente me guardo las contraseñas de los schemas con la query que muestro debajo:

SELECT name,password FROM SYS.USER$ WHERE password is not null;


Nota: cuando hacemos el duplicado con la opción ACTIVE DATABASE de RMAN hay un par de prerequisitos a tener en cuenta:
  • Source destination tiene que estar en ARCHIVELOG.
  • Tanto en el source como en el destino tienen que tener agregado el tnsnames.ora con la configuración de la base de datos a duplicar.
  • El password file debe estar replicado en ambos equipos.
  •  crear un init.ora con al menos estos parametros
          *.db_name='DBCLON
          *.db_file_name_convert=('+DATAORIGEN','+DATADESTINO)
          *.log_file_name_convert=('+DATAORIGEN,'+DATADESTINO')
  • Tener en cuenta que si se cambia el password de sys hay que volver a copiar el orapw.
  • Crear un listener_estatico en algun  puerto libre.
  • Agregar la entrada del listener en el tnsnames.ora local.

Pasos a seguir:

Aqui estamos logueados en el servidor de la instancia que queremos clonar.
  • Bajar la instancia a clonar
  • Tomar backup del spfile actual mv spfileBDCLON spfileCLON.old
  • Desde el nodo destino startup nomount de la instancia  DBCLON .
  • Borrar todo lo que contenga el diskgroup +DATADESTINO

Aqui estamos logueados en el nodo origen donde tenemos nuestra instancia productiva

Desde el nodo origen nos conectarnos al rman y ejecutar el script.

NOTA: Si esta conexion 1 no funciona usar la 2

export ORACLE_SID=DBORIGEN

1- rman target / auxiliary sys/password@DBCLON

2- rman target usuario/pasword@DBORIGEN auxiliary sys/password@DBCLON


Luego una vez dentro del rman ejecutar el script que hace el clonado de la instancia.

run {
   allocate channel prmy1 type disk; 
   allocate auxiliary channel clondb type disk; 
   duplicate target database to CLONDB from active database nofilenamecheck
logfile
  group 1 ('+ DATADESTINO /redo01.log') size 50M,
  group 2 ('+ DATADESTINO /redo02.log') size 50M,
  group 3 ('+ DATADESTINO /redo03.log') size 50M,
  group 4 ('+ DATADESTINO /redo04.exilog') size 50M;
}

Luego una vez terminado el restore , crear un spfile para la instancia, cambiar la password de sys y system, frenar los jobs si es que existen y todo lo que haga falta para tener un ambiente de test en forma operativa.

FIN.


lunes, 5 de julio de 2010

Como habilitar la opción de DEBUG en el TOAD?

Pasos

El usuario necesita tener el privilegio 'DEBUG CONNECT SESSION'. Si el mismo no fue granteado, el icono de debugger estará deshabilitado en el editor de pl/sql.


Solución

1. Grant debug any procedure to user_name;
2. Grant debug connect session to user_name;

Si es necesario tambien ejecutar:

1. GRANT EXECUTE ON DBMS_DEBUG to public;
2. Si, DBMS_DEBUG no esta creado, ejecutar el archivo $ORACLE_HOME\rdbms\admin\prvtpb.plb con el usuario SYS.

jueves, 17 de junio de 2010

Configurar Toad y sqlplus, usando Oracle Instant Client


Instant Client Package – Basic
Instant Client Package - SQL*Plus

Paso 2. Creamos cuatro carpetas como se muestra debajo.

C:\oracle
C:\oracle\bin
C:\racle\network
C:\oracle\network\admin
Paso 3. Descomprimimos los binarios dentro de c:\oracle\bin y nos aseguramos que exita el archivo oci.dll y sqlplus.exe.
Luego dentro de la carpeta admin alojamos los archivos tnsnames.ora y sqlnet.ora

tnsnames.ora


ALIAS_XE =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = x.x.x.x)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = XE)
)

sqlnet.ora

SQLNET.AUTHENTICATION_SERVICES = (NTS)

Paso 4. Creamos las siguientes variables de sistema. Vamos a mi pc > propiedades > configuración avanzada del sistema > Variables de entorno


Y agregamos:

ORACLE_HOME = C:\oracle
ORACLE_HOME_NAME = C:\oracle
SQL_PATH = C:\oracle
TNS_ADMIN = C:\oracle\network\admin
LD_LIBRARY_PATH = C:\oracle\bin
PATH= C:\oracle\bin;

Paso 5. Probamos hacer la conexión con el Toad y el sqlplus.

jueves, 5 de noviembre de 2009

Como particionar una tabla en linea?

Supongamos que tenemos una tabla, esta puede estar o no particionada y la idea en este caso puntual es volver a particionarla por mes con creación de particiones en forma automática. Para esta tarea vamos a utilizar el pakage DBMS_REDEFINITION.

paso 1.

El primer paso es chequear si la tabla se puede redefinir online, si la salida del script mostrado debajo no da ningún error, entonces podemos hacer uso del packages DBMS_REDEFINITION.

DECLARE
ndummy NUMBER;
begin
DBMS_REDEFINITION.CAN_REDEF_TABLE('SCHEMA','TABLA_ORIGINAL');
EXCEPTION
WHEN OTHERS THENRAISE;
end;
/

Paso 2.

Creamos la tabla temporal con la nueva estructura, en mi caso sólo la particioné por otro campó y ademas lo hice por mes utilizando la clausula "INTERVAL( NUMTOYMINTERVAL(1,'MONTH'))" provista en 11g la cual hace que las partiones se creen en forma automática.

NOTA:
- Para no generar archive's cambiar a modo NOLOGGING tanto la definición de la tabla como el clob.
- Crear las particiones necesarias para alojar la tabla completa.
- Hay que asegurarnos de tener espacio en el tablespace, mínimo el tamaño de la tabla original y un poco más.
- Debe tener la misma PK que la Original.
- En este punto no se debe crear ningún indice ni constraint ni trigger que no sea la PK.
- La tabla debe ser creada con los cambios deseados. - La tabla temporal debe ser creada con esos cambios.

--prompt creo la tabla temporal

CREATE TABLE SCHEMA.DOCUMENTOS_TEMP
(
IDNS_DOCUMENTO NUMBER NOT NULL,
SD_ANIO NUMBER(4) NOT NULL,
SD_ADUANA VARCHAR2(3 CHAR) NOT NULL,
SD_DOCUMENTOTIPO VARCHAR2(4 CHAR) NOT NULL,
SD_DOCUMENTONRO VARCHAR2(6 CHAR) NOT NULL,
SD_LETRA VARCHAR2(1 CHAR) NOT NULL,
SG_DOCUMENTO BLOB NOT NULL,
SD_CAJA VARCHAR2(6 CHAR) NOT NULL,
NS_DESPACHANTE NUMBER NOT NULL,
SD_CUITDESPACHANTE VARCHAR2(11 CHAR) NOT NULL,
SD_DESPACHANTE VARCHAR2(100 CHAR) NOT NULL,
NS_IMPORTADOREXPORTADOR NUMBER NOT NULL,
SD_CUITIMPORTADOREXPORTADOR VARCHAR2(11 CHAR) NOT NULL,
SD_IMPORTADOREXPORTADOR VARCHAR2(100 CHAR) NOT NULL,
H_ALTA DATE DEFAULT SYSDATE NOT NULL,
NC_PAGINAS NUMBER(4) NOT NULL,
NC_PAGINASLOTE NUMBER(4),
NC_BYTESPDF NUMBER,
H_UPD DATE
)
TABLESPACE DATA_CLOB
NOLOGGING
PARTITION BY RANGE (H_ALTA)
INTERVAL( NUMTOYMINTERVAL(1,'MONTH'))
(
PARTITION VALUES LESS THAN (TO_DATE(' 2009-09-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
NOLOGGING
NOCOMPRESS
TABLESPACE DATA_CLOB
LOB (SG_DOCUMENTO) STORE AS
( TABLESPACE DATA_CLOB
ENABLE STORAGE IN ROW
CHUNK 8192
RETENTION
NOCACHE
NOLOGGING
),
PARTITION VALUES LESS THAN (TO_DATE(' 2009-10-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
NOLOGGING
NOCOMPRESS
TABLESPACE DATA_CLOB
LOB (SG_DOCUMENTO) STORE AS
( TABLESPACE DATA_CLOB
ENABLE STORAGE IN ROW
CHUNK 8192
RETENTION
NOCACHE
NOLOGGING
),
PARTITION VALUES LESS THAN (TO_DATE(' 2009-11-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
NOLOGGING
NOCOMPRESS
TABLESPACE DATA_CLOB
LOB (SG_DOCUMENTO) STORE AS
( TABLESPACE DATA_CLOB
ENABLE STORAGE IN ROW
CHUNK 8192
RETENTION
NOCACHE
NOLOGGING
),
PARTITION VALUES LESS THAN (TO_DATE(' 2009-12-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
NOLOGGING
NOCOMPRESS
TABLESPACE DATA_CLOB
LOB (SG_DOCUMENTO) STORE AS
( TABLESPACE DATA_CLOB
ENABLE STORAGE IN ROW
CHUNK 8192
RETENTION
NOCACHE
NOLOGGING
)
)
NOCOMPRESS
NOCACHE
NOPARALLEL
MONITORING;


Paso3.

Asociamos la tabla temporal con la tabla a redefinir.

prompt Iniciar el proceso de redefinición
BEGIN
DBMS_REDEFINITION.START_REDEF_TABLE ('SCHEMA','DOCUMENTOS','DOCUMENTOS_TEMP',
'IDNS_DOCUMENTO IDNS_DOCUMENTO,
SD_ANIO SD_ANIO,
SD_ADUANA SD_ADUANA,
SD_DOCUMENTOTIPO SD_DOCUMENTOTIPO,
SD_DOCUMENTONRO SD_DOCUMENTONRO,
SD_LETRA SD_LETRA, SG_DOCUMENTO
SG_DOCUMENTO, SD_CAJA SD_CAJA,
NS_DESPACHANTE NS_DESPACHANTE,
SD_CUITDESPACHANTE SD_CUITDESPACHANTE,
SD_DESPACHANTE SD_DESPACHANTE,
NS_IMPORTADOREXPORTADOR NS_IMPORTADOREXPORTADOR, SD_CUITIMPORTADOREXPORTADOR SD_CUITIMPORTADOREXPORTADOR, SD_IMPORTADOREXPORTADOR SD_IMPORTADOREXPORTADOR,
H_ALTA H_ALTA,
NC_PAGINAS NC_PAGINAS,
NC_PAGINASLOTE NC_PAGINASLOTE,
NC_BYTESPDF NC_BYTESPDF,
H_UPD H_UPD',
dbms_redefinition.cons_use_pk);
END;
/

Paso4.

Copia las dependencias de la tabla original a la tabla temporal.

prompt Copiar el objeto dependiente

DECLARE
num_errors PLS_INTEGER;
BEGIN
DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS('SCHEMA', 'DOCUMENTOS','DOCUMENTOS_TEMP', DBMS_REDEFINITION.CONS_ORIG_PARAMS, TRUE, TRUE, TRUE, TRUE, num_errors);
END;
/


Paso5.

Hacemos un chequeo de errores.
prompt Consultar la vista DBA_REDEFINITION_ERRORS para saber si hubo algún error.

select object_name, base_table_name, ddl_txt from DBA_REDEFINITION_ERRORS;
Paso6.
Mantenemos sincronizada la tabla temporal con los datos de la tabla original.

prompt Sincronizar la tabla temporal o intermedia

BEGIN
DBMS_REDEFINITION.SYNC_INTERIM_TABLE('SRD', 'DOCUMENTOS','DOCUMENTOS_TEMP');
END;
/


Paso7.

Registra la dependendia de objetos ( indices, trigger o constraint ) y finaliza la redefinición.

prompt Completar la redefinicion

BEGIN
DBMS_REDEFINITION.FINISH_REDEF_TABLE('SRD', 'DOCUMENTOS','DOCUMENTOS_TEMP');
END;
/

Paso8.

Volver a poner en modo LOGGING a la tabla.

alter table SCHEMA.DOCUMENTOS LOGGING ;
alter table SCHEMA.DOCUMENTOS MODIFY LOB (SG_DOCUMENTO) (CACHE LOGGING);

NOTA:

En caso de dar error y querer realizar rollback de la operacion se puede ejecutar lo siguente

BEGIN dbms_redefinition.abort_redef_table('SRD', 'DOCUMENTOS','DOCUMENTOS_TEMP');
END;
/

martes, 19 de mayo de 2009

Como mover datos de la partición default a una nueva?

Cuando tenemos una tabla particionada, en este caso por un rango de fechas y nos damos cuenta que los registros se están creando en la partición default, la solución es crear una nueva particion con el rango adecuado. Para este caso se puede usar la opción SPLIT la cual crea una nueva partición, en mi caso es la partición DCT_DOC2009.

ALTER TABLE dct_documentos
SPLIT PARTITION DCT_DOCMAX at (TO_DATE(' 2010-01-02 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
INTO (PARTITION DCT_DOC2009,
PARTITION DCT_DOCMAX)
UPDATE GLOBAL INDEXES;

Podemos usar la opción UPDATE GLOBAL INDEXES la cual recrea los indices globales de la tabla en cuestión o podriamos eliminar la opción de la claúsula y en un segundo paso recrear los indices con estado UNSUABLE.

Para hacer el reubuild de los indices usamos la siguiente query:

SELECT 'alter index 'owner'.'index_name ' REBUILD;'
FROM dba_indexes
WHERE status='UNUSABLE' ;

Para ver como quedaron las particiones se puede usar el siguiente query:

SELECT partition_name, high_value
FROM user_tab_partitions
WHERE table_name = 'DCT_DOCUMENTOS'
ORDER BY partition_name;

Para confirmar que ahora la partición tiene datos usamos:

SELECT * FROM dct_documentos PARTITION(DCT_DOC2009);

Par confirmar que la particion default en mi caso se llama DCT_DOCMAX, esta query debería no retornar filas.

SELECT * FROM dct_documentos PARTITION(DCT_DOCMAX);

Como calcular el tamaño realmente usado de un segmento

Con este script se puede calcular el tamaño realmente usado por un segmento.


PROMPT
PROMPT SEGMENT SPACE ALLOCATION
PROMPT

ACCEPT own PROMPT "Segment owner: "
ACCEPT obj PROMPT "Segment name: "
ACCEPT typ PROMPT "Segment type ((T)able, (I)ndex or (C)luster) or (L)ob: "

SET HEADING OFF
SELECT ' ' FROM sys.dual;

SET SERVEROUTPUT ON

DECLARE
op1 NUMBER;
op2 NUMBER;
op3 NUMBER;
op4 NUMBER;
op5 NUMBER;
op6 NUMBER;
op7 NUMBER;
obj_type VARCHAR2(10);
file_name VARCHAR2(255);
ts_name VARCHAR2(30);

BEGIN

IF UPPER('&typ') = 'T' THEN
obj_type := 'TABLE';
ELSIF UPPER('&typ') = 'I' THEN
obj_type := 'INDEX';
ELSIF UPPER('&typ') = 'C' THEN
obj_type := 'CLUSTER';
ELSIF UPPER('&typ') = 'L' THEN
obj_type := 'LOB';

ELSE
dbms_output.put_line('Invalid object type');
RETURN;
END IF;

dbms_space.unused_space(
UPPER('&own'),
UPPER('&obj'),
obj_type,
op1, op2, op3, op4, op5, op6, op7
);

dbms_output.put_line('Total Blocks = ' || op1);
dbms_output.put_line('Total Bytes = ' || op2);
dbms_output.put_line('Unused Blocks = ' || op3);
dbms_output.put_line('Unused Bytes = ' || op4);

SELECT file_name, tablespace_name
INTO file_name, ts_name
FROM dba_data_files
WHERE file_id = op5;

dbms_output.put_line('Segment Tablespace = ' || ts_name);
dbms_output.put_line('Last Used Extent File ID = ' || op5);
dbms_output.put_line('Last Used Extent File = ' || file_name);
dbms_output.put_line('Last Used Extent Block ID = ' || op6);
dbms_output.put_line('Last Used Block = ' || op7);

END;
/

UNDEFINE obj
UNDEFINE own
UNDEFINE typ

lunes, 18 de mayo de 2009

Como reducir el tamaño del tablespace UNDO

El procedimiento que muestro a continuación, muestra los pasos a seguir cuando tenemos que recrear el tablespace UNDO en un ambiente RAC.

Estamos trabajando con un cluster de dos nodos que contienen dos Instancias de bases de datos.

Los tablespaces de UNDO de una de las instancias han crecido más de la cuenta y nos han llenado el disco.

NOTA:Una base de datos solo puede tener un tablespace de UNDO activo en un momento determinado.

En un entorno RAC, tenemos un tablespace de UNDO para cada instancia.

Un tablespace no se puede reducir de tamaño. Lo que voy a hacer es eliminarlo y volver a crearlo con un tamaño adecuado, añadiendo además un límite a su crecimiento. El problema que tengo ahora es que estoy tratando con un tablespace de UNDO, el cual tiene un tratamiento especial.

No se puede poner offline y menos aún borrarlo mientras tenga segmentos activos. De modo que, lo primero es crear un nuevo tablespace de undo, las instrucciones que indico a continuación las ejecuto como usuario SYS:


Paso 1.

CREATE UNDO TABLESPACE UNDO_TEMPORAL DATAFILE SIZE 100M;

Ahora en la primera instancia del cluster (el orden da igual) se indica el parámetro que indica el tablespace de undo por defecto.

En este caso, se trata de un parámetro dinámico, y por lo tanto no hace falta parar la instancia para poder modificarlo:

ALTER SYSTEM SET UNDO_TABLESPACE='UNDO_TEMPORAL' SID='DB1';

Si ahora reviso los parámetros que hacen referencia al UNDO en esta instancia, me encuentro con lo siguiente:

Paso2.

sqlplus> show parameter undo

NAME TYPE VALUE
—————— ———– ——————–
undo_management string AUTO
undo_retention integer 900
undo_tablespace string UNDO_TEMPORAL

En teoría, ya puedo borrar el tablespace de undo que me estaba dando el problema.

Si se diera la condición de que todos los segmentos estuvieran en estado offline, no haría ni siquiera falta poner offline el tablespace; le podría hacer un drop sin más complicaciones. El problema viene cuando hay algún segmento que no está offline; teniendo claro que no quiero hacer rollback, ni recuperar ningún tipo de transacción, y que puedo prescindir totalmente de estos datos, lo que voy a hacer es forzar el estado offline de los segmentos que no lo estén para poder borrar el tablespace de forma limpia. ¿Cómo compruebo esto? Con la siguiente select:


Paso3.

SELECT SEGMENT_NAME,TABLESPACE_NAME,STATUS
FROM DBA_ROLLBACK_SEGS
WHERE TABLESPACE_NAME='UNDOTBS1';

Que me dará un resultado como el que sigue:
SEGMENT_NAME TABLESPACE_NAME STATUS
——————– ————————- —————-
_SYSSMU13$ UNDOTBS1 NEEDS RECOVERY
_SYSSMU14$ UNDOTBS1 OFFLINE
_SYSSMU15$ UNDOTBS1 OFFLINE
_SYSSMU16$ UNDOTBS1 OFFLINE
_SYSSMU17$ UNDOTBS1 NEEDS RECOVERY
_SYSSMU18$ UNDOTBS1 OFFLINE
_SYSSMU19$ UNDOTBS1 OFFLINE
_SYSSMU20$ UNDOTBS1 OFFLINE

Cualquier status diferente de OFFLINE necesitará que le apliquemos el procedimiento que a continuación describo.

Paso4.

Lo siguiente es bajar la instancia; por suerte, estoy en un entorno RAC, por lo tanto no va a haber pérdida de servicio.

Como tengo que arrancar con un PFILE modificado a partir del SPFILE (con el que estoy trabajando), voy a crear un PFILE antes de bajar la instancia:


CREATE PFILE='/tmp/pfile.ora' from SPFILE;

Ahora bajo la instancia y edito el PFILE. Tengo que modificar el parámetro UNDO_MANAGEMENT al valor 'MANUAL' y añadir un parámetro oculto de ORACLE

para poder forzar el OFFLINE de los segmentos UNDO que no lo estén. Para el caso que describo, y según la anterior SELECT, yo insertaría esta línea

en mi PFILE:

*._offline_rollback_segments="_SYSSMU13$,_SYSSMU17quot;

Lo siguiente es levanter la instancia con el PFILE modificado:

STARTUP PFILE='/tmp/pfile.ora'

Si se ejecuta la anterior select, el resultado va a ser el mismo. Pero ahora ya se puede actuar sobre esos segmentos. En primer lugar:

DROP ROLLBACK SEGMENT '_SYSSMU13;

Que dará un resultado como este:

ERROR en línea 1:
ORA-02175: nombre de segmento de rollback no válido

Obviamos el error y repetimos el DROP sobre el otro segmento. Después de eso, ya se puede borrar el segmento de undo:


DROP TABLESPACE UNDOTBS1 INCLUDING CONTENTS AND DATAFILES;

Una vez borrado este tablespace, vuelvo a parar la instancia y arranco con el SPFILE (hago un startup sin ningún parámetro). En este momento,

ya puedo crear el nuevo tablespace de undo con los parámetros deseados:

CREATE UNDO TABLESPACE UNDOTBS1 DATAFILE SIZE 500M AUTOEXTEND ON NEXT 128M MAXSIZE 1G;

Igual que he hecho antes, cambio el tablespace de UNDO por defecto, substituyendo UNDO_TEMPORAL por UNDOTBS1.

ALTER SYSTEM SET UNDO_TABLESPACE='UNDOTBS1' SID=’DB1’;

Finalmente, solo queda repetir el proceso con la otra instancia. Cuando se concluya, se puede borrar el tablespace de UNDO que se ha creado para solucionar el problema.

viernes, 30 de enero de 2009

Restore completo base de datos con RMAN.

1- Suponiendo que disponemos de un backup a disco en el directorio /pruebarman
2. Iniciar una sesión desde un terminal del servidor como usuario oracle
3. Conectarse al RMAN:

$ rman target / nocatalog

4. Iniciar la base de datos sin montarla y restaurar el pfile utilizando el autobackup:

RMAN> set DBID=248804095;
startup nomount;
run
{
restore spfile to pfile '/oracle/product/10.2.0/dbs/initBAIHONT.ora' from '/pruebarman/c-248804095-20090130-04';
shutdown abort;
}

5. Iniciar la base de datos utilizando el pfile restaurado.
RMAN> set DBID=248804095;
RMAN> startup force nomount pfile = '/oracle/product/10.2.0/dbs/initBAIHONT.ora';

6. Restaurar los archivos de control e la base de datos (control files)
run
{
restore controlfile from '/pruebarman/c-248804095-20090130-04';
alter database mount;
}

7. Restaurar los archivos de base de datos (data files) y restaurar la data al día del backup utilizado.
run
{
restore database;
switch datafile all;
recover database;
}

8. Inicializar la base de datos para un normal funcionamiento.
RMAN> alter database open resetlogs;

9. Comprobar el funcionamiento de la base de datos restaurada, para ello se realizaran prueba de conexión a la base de datos:
$ sqlplus / as sysdba
SQL> connect system;
SQL> connect [usuario diferente al sys o system];

jueves, 20 de noviembre de 2008

Como desparticionar una tabla rápidamente

Si se quiere desparticionar una tabla muy grande, en donde sacar un export y volverlo a subir con la estructura de la tabla sin particiones se vuelve un método demasiado lento, podemos utilizar los siguientes pasos para que el proceso se haga mucho más rápido:

Paso 1.- Primero se debe hacer un merge de las particiones existentes en una sola, esto se logra con la siguiente sentencia:


sql> ALTER TABLE tabla_particionada MERGE PARTITIONS part1, (part2,part3) INTO ultima_particion;


Para saber el nombre de las particiones puede utilizar la sentencia que se detalla a continuación:


sql> SELECT PARTITION_NAME FROM USER_TAB_PARTITIONS WHERE TABLE_NAME=tabla_particionada;


Consultar el número de registros existentes actualmente en la tabla para una posterior comprobación. (select count(*) from tabla_particionada)


Paso 2.- Crear la tabla con un nombre temporal (tabla_desparticionada) y sin particiones.


Paso 3.- Pasar los datos de la tabla particionada a la nueva tabla creada sin particiones:


sql> ALTER TABLE tabla_particionada EXCHANGE PARTITION ultima_particion WITH TABLE tabla_desparticionada INCLUDING INDEXES WITHOUT VALIDATION;


Paso4.- Comprobar que la tabla creada sin particiones (tabla_desparticionada) tiene ahora el mismo número de registros que tenía antes la tabla particionada. Esta última debería tener ahora 0 registros como consecuencia de la migración. Si se migraron correctamente los registros, se deberá finalmente borrar la tabla particionada (verificar antes dependencias con otros objetos) y renombrar a la tabla sin particiones con el nombre original.


Paso 5.- Renombrar la tabla:
sql> ALTER TABLE tabla_desparticionada RENAME TO nuevo_nombre;

Cómo recrear un tablespace con datos

En algunas oportunidades nos podemos encontrar con la necesidad de recrear un talespace que ya contiene datos, como por ejemplo cuando queremos cambiar una opción del tablespace , la cual la sentencia “alter tablespace” no nos permite modificar. En estos casos podemos seguir los siguientes pasos para re-crear el tablespace sin perder los datos que contiene el mismo, de una forma sencilla:

Paso 1.- Primero confirmamos el espacio ocupado por el tablespace actualmente:
sql>select sum(bytes)/1024/1024 MB from user_segments where tablespace_name = 'tbsname';

Paso 2.- Exportar los datos existentes en el tablespace que se desea recrear:
# exp system/psswd tablespaces=tbsname compress=n direct=y file=nombre.dmp log=nombre.log;

Paso 3.- Borrar el tablespace, desde el Enterprise Manager o via comandos:
sql> drop tablesapce tbsname including contents and datafiles;

Paso 4.- Recrear el tablespace. En este caso, por ejemplo, se quería cambiar la clausula de “segment space management” de manual a auto. De igual forma se puede re-crear el TBS vía EM o por linea de comandos:
sql> create tablespace tbsname datafile '/…./…dbf' size 20M autoextend on next 2048K maxsize 4000M logging extent management local segment space management auto;

Paso 5.- Importar el tablespace:
# imp system/psswd full=y file=nombre.dmp log=nombre.log tablespaces=tbsname rows=y indexes=y constraints=y commit=y ignore=y grants=n buffer=500000
Y con eso ya tendríamos los datos.

Paso 6.- Finalmente deberíamos comprobar que existe la misma cantidad de información el TBS luego de realizar el import:
sql>select sum(bytes)/1024/1024 MB from user_segments where tablespace_name = 'tbsname';

lunes, 15 de septiembre de 2008

Descubrir que Query hace mas Rollback

La manera mas rápida para descubrir la query que está generando demasiado Rollback podría ser:

1.- Buscamos las sesiones que estan generando mucho Rollback, usa la siguiente query:

col sid format 9999999

select t.*,n.NAMEfrom v$sesstat t,V$STATNAME n
where t.STATISTIC# = 5 --Donde 5 corresponde al # de estadistica de los rollbacks
and t.STATISTIC# = n.STATISTIC#
and value > 50;

2.- Luego con el SID, se busca el HASH_VALUE, que es el identificador de cada Query dentro del motor de Oracle, para esto usar la siquiente Query:

select s.SQL_HASH_VALUE, s.*
from v$session s
where sid = &SID;

3.- Una vez que encontramos el HASH_VALUE ahora debemos encontrar la query y listo, para esto usamos la siguiente Query:

select *from v$sql s
where s.HASH_VALUE = &HASH_VALUE;

martes, 9 de septiembre de 2008

ORA-01092: ORACLE instance terminated. Disconnection forced

Hace poco tuve un inconveniente algo extraño con mi base de datos Oracle 10g. El error se presentó luego de poner a mi base de datos en modo ARCHIVELOG, al pasar del estado MOUNT al OPEN saltó el siguiente error:

ORA-01092 ORACLE instance terminated. Disconnection forced


Intenté quitarle el modo ARCHIVELOG e intentar volver a subir la base, pero esto no funcionó.

Cada que vez que la intentaba subir de cualquier forma me daba el mismo error. Revisando respecto a este error solo encontré que puede suceder por una bajada no limpia de la base (por ejemplo un SHUTDOWN ABORT) y que la solución es esperar un tiempo e intentar volver a subir la base, pero inclusive re-inicié el equipo donde reside la base y esto no funcionó. Al consultar el alert_log para tener algún tipo de información adicional encontré el siguiente error:

ORA-30012: undo tablespace ‘UNDOTBS1′ does not exist or of wrong type

Lo cual claramente me indica que existe algún tipo de problema con mi tablespace de UNDO. Entonces, partiendo de esto realicé los siguientes pasos para poder levantar mi base:


1) Subir a la base en estaus NO MOUNT:

SQL> startup nomount;


2) Cambiar el parámetro UNDO_TABLESPACE para que no apunte al TBS de undo con problemas y así permitir que la base sea abierta:

SQL> alter system set UNDO_TABLESPACE=”;

3) Subir a la base de datos:

SQL> alter database mount;SQL> alter database open;


4) Con la base abierta creamos un nuevo tablespace de UNDO:

SQL> create undo tablespace UNDOTBS2 datafile ‘/home/oracle/admin/oradata/db10g/datafiles /undotbs2.dbf’ size 200M autoextend on maxsize 1024M;


5)Modificamos nuevamente al parámetro UNDO_TABLESPACE para que apunte al nuevo tablespace de UNDO (luego de esto podemos borrar al tablespace que estaba dando problemas):

SQL> alter system set UNDO_TABLESPACE=’UNDOTBS2′;SQL> drop tablespace UNDOTBS1 including contents and datafiles;

6)Bajamos limpiamente la base y la volvemos a subir:

SQL> shutdown immediate;SQL> startup;

Y listo!! Con esto la base de datos se encuentra arriba nuevamente. Luego logré ponerla a trabajar en modo ARCHIVELOG sin problemas.

martes, 2 de septiembre de 2008

Cambio de password del usuario "oc4jadmin" del iasR3.

Para modificar las claves del usuario "oc4jadmin", hay que actualizar las lineas de los archivos system-jazn-data.xml de los contedores, antes hacer una copia de los viejos por las dudas.

El archivo "system-jazn-data.xml" se encuentra en el directorio config del contenedor correspondiente ($ORACLE_HOME/j2ee/home/config/system-jazn-data.xml).

Pasos:
1- Bajar los contenedores a modificar.

2- En las lineas del usuario "oc4jadmin" del archivo system-jazn-data.xml:
{903}z0jYUSxW3jZeOyMHUHr7whDJoPni2XXu
modificarlas, por:
!oc4jadmin_password.

Donde oc4jadmin_password es la nueva clave del usuario, en la versión IasR3 debe ser la misma para todas las instancias, si se utiliza oc4jadminpara adminstrar todas las instancias.

3- Subir el contenedor modificado. Y probar loguearse para encriptar el dato en el archivo.

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;