Hoy amanecimos con un disco menos en el servidor, y la base de datos (un 9.2 en RAC) nos avisó que no podía acceder a un logfile de determinado thread y grupo.
Cómo los logfiles están cruzados en diferentes unidades de disco (justamente para prevenir estas fallas físicas de disco) tuve que eliminar los logfiles que figuraban como inválidos en la vista V$LOGFILE y a su vez reconstruirlos en otro FS, como se ejemplifica a continuación:
alter database drop logfile member '<ruta>/<logfile>';
alter database add logfile member '<ruta nueva>/<logfile>' reuse to group <grupo>
Cuidado, si algún drop falla, probablemente es porque ese logfile esté siendo utilizado por la base, en ese preciso momento, con lo cual podemos esperar o forzar el switch a otro redo, con alter system switch logfile; tal vez tengamos que ejecutar esta sentencia más de una vez, para que finalmente se pueda hacer el drop.
Si todo esto fué bien y consultamos la V$LOGFILE y nos figura alguno de los nuevos logfile como invalido, puede ser porque la instancia ya esté utilizando ese grupo de redo, con lo cual devuelta ejecutamos una o más veces el alter system switch logfile y con esto se debería solucionar, salvo que haya otro problema de fondo, por lo que no pueda ser utilizado el nuevo archivo, por ejemplo la nueva ubicación también tiene sectores inválidos.
miércoles, 17 de marzo de 2010
ORACLE: Segmento temporal
Esta es una interesante consulta para echarle un vistazo al segmento temporal (en un 9.2.0)
SELECT ses.inst_id,
ses.sid,
ses.serial#,
ses.username,
ses.status,
ses.machine,
ses.program,
seg.blocks,
txt.piece,
txt.sql_text
FROM gv$session ses,
gv$tempseg_usage seg,
gv$sqltext txt
WHERE seg.blocks > 32
AND seg.sqladdr = txt.address
AND seg.sqlhash = txt.hash_value
AND seg.session_addr = ses.saddr
AND seg.session_num = ses.serial#
and seg.inst_id = ses.inst_id
and seg.inst_id = txt.inst_id
ORDER BY seg.blocks,
txt.piece;
Encontré este enlace que me pareció muy útil.
SELECT ses.inst_id,
ses.sid,
ses.serial#,
ses.username,
ses.status,
ses.machine,
ses.program,
seg.blocks,
txt.piece,
txt.sql_text
FROM gv$session ses,
gv$tempseg_usage seg,
gv$sqltext txt
WHERE seg.blocks > 32
AND seg.sqladdr = txt.address
AND seg.sqlhash = txt.hash_value
AND seg.session_addr = ses.saddr
AND seg.session_num = ses.serial#
and seg.inst_id = ses.inst_id
and seg.inst_id = txt.inst_id
ORDER BY seg.blocks,
txt.piece;
Encontré este enlace que me pareció muy útil.
jueves, 7 de enero de 2010
ORACLE: Bloqueante y bloqueado de un objeto de base de datos.
Basándome en el query que pasaron en este foro completé un poco más la información obtenida, agregándole la sentencia que está bloqueando, y la bloqueada.
SELECT LPAD (' ', DECODE (l.xidusn, 0, 8, 0))
|| l.oracle_username "User Name",
o.owner, o.object_name, o.object_type, l.locked_mode, st.sql_text
FROM v$locked_object l,
dba_objects o,
v$session s,
v$sqltext_with_newlines st
WHERE l.object_id = o.object_id
AND l.session_id = s.SID
AND ( ( l.xidusn = 0
AND st.address = s.sql_address
AND st.hash_value = s.sql_hash_value
)
OR ( l.xidusn <> 0
AND st.address = s.prev_sql_addr
AND st.hash_value = s.prev_hash_value
)
)
ORDER BY o.object_id, 1 DESC, st.piece;
SELECT LPAD (' ', DECODE (l.xidusn, 0, 8, 0))
|| l.oracle_username "User Name",
o.owner, o.object_name, o.object_type, l.locked_mode, st.sql_text
FROM v$locked_object l,
dba_objects o,
v$session s,
v$sqltext_with_newlines st
WHERE l.object_id = o.object_id
AND l.session_id = s.SID
AND ( ( l.xidusn = 0
AND st.address = s.sql_address
AND st.hash_value = s.sql_hash_value
)
OR ( l.xidusn <> 0
AND st.address = s.prev_sql_addr
AND st.hash_value = s.prev_hash_value
)
)
ORDER BY o.object_id, 1 DESC, st.piece;
lunes, 4 de enero de 2010
Pro*C: dbms_output.put_line
No sé por qué nunca se me ocurrió esto, pero bueh.
Nosotros estamos acostumbrados a sacar mensajes desde un PL/SQL siempre y cuando usemos el sqlplus:
$ sqlplus ***/***
SQL> set serveroutput on; <=== para que se vean los mensajes que mostremos con el dbms_output
SQL> begin
2 dbms_output.enable(null); <=== para habilitar un buffer sin límites
3 dbms_output.put_line('Hola Quique'); <=== "muestra el texto por pantalla" (nótese las comillas)
4 end;
5 / hola PL/SQL procedure successfully completed.
SQL>
Ahora, la incognita errónea que siempre nos preguntamos o al menos yo lo hice es, cómo implementamos la instrucción "set serveroutput on" desde Pro*C, si este es un comando de sqlplus? Y ete aquí que lo que está mal formulada es la pregunta o el concepto del put_line. put_line no muestra un texto, sino que pone un texto dentro del buffer habilitado con enable, entonces ahora pensando que tenemos un almacen de textos en memoria, lo que nos queda es recuperarlo de ese almacen, y si alguna vez se te dá por leer los manuales de PL/SQL, vas a ver que el package dbms_output tiene varias rutinas, entre ellas el bendito get_line(), quien se encarga de obtener ese texto del buffer! Entonces ahora sí estoy en condiciones de utilizar el dbms_output desde Pro*C! Acá va el ejemplo:
exec sql begin declare section;
varchar vcTexto[40000];
short indTexto;
int iStat;
short indStat;
exec sql end declare section;
...
memset(&vcTexto, (int)NULL, sizeof(vcTexto));
exec sql execute
begin
dbms_output.enable(null);
dbms_output.put_line('Hola mundo desde PL/SQL');
dbms_output.get_line(:vcTexto:indTexto, :iStat:indStat);
end;
end-exec;
if(indTexto==0) printf("%s\n", vcTexto.arr);
Otro ejemplo (en este recupero el texto en otro bloque, pero como la sesion es la misma, el buffer prevalece y por ende su contenido):
exec sql begin declare section;
varchar vcTexto[40000];
short indTexto;
int iStat;
short indStat;
exec sql end declare section;
...
exec sql execute
begin
dbms_output.enable(null);
dbms_output.put_line('Hola mundo desde PL/SQL');
end-exec;
memset(&vcTexto, (int)NULL, sizeof(vcTexto));
exec sql execute
begin
dbms_output.get_line(:vcTexto:indTexto, :iStat:indStat);
end;
end-exec;
if(indTexto==0) printf("%s\n", vcTexto.arr);
Tercer y último ejemplo:
Dentro de una rutina almacenada, lo lleno de mensajes en todas las posibles salidas de error/exception.
SQL> create or replace procedure Quique is
2 begin
3 FOR i IN 1..100 LOOP
4 dbms_output.put_line(RPAD('*',1000,'*'));
5 END LOOP;
6 end;
7 /
Procedure created.
SQL>
e invoco la rutina desde el Pro*C, de esta forma:
exec sql begin declare section;
varchar vcTexto[40000];
short indTexto;
int iStat;
short indStat;
exec sql end declare section;
...
memset(&vcTexto, (int)NULL, sizeof(vcTexto));
exec sql execute
begin
dbms_output.enable(null);
Quique;
end;
end-exec;
while(iStat==0) {
memset(&vcTexto, (int)NULL, sizeof(vcTexto));
exec sql execute
begin
dbms_output.get_line(:vcTexto:indTexto, :iStat:indStat);
end;
end-exec;
if(indStat<0) istat = 1;
if(indTexto==0)
printf("%s\n", vcTexto.arr);
}
Cuando el buffer quede vacío, iStat contendrá el valor uno.
Cómo dice el manual, hay que declarar una variable huesped de tipo varchar no inferior a 32767, de lo contrario emitirá el error ora-6502.
Ojo! Si entre lecturas del buffer con get_line, se invoca un put_line, éste vacía el buffer con lo cual se pierde el resto de las lecturas previas al put_line.
http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_output.htm#BABGBACJ
Nosotros estamos acostumbrados a sacar mensajes desde un PL/SQL siempre y cuando usemos el sqlplus:
$ sqlplus ***/***
SQL> set serveroutput on; <=== para que se vean los mensajes que mostremos con el dbms_output
SQL> begin
2 dbms_output.enable(null); <=== para habilitar un buffer sin límites
3 dbms_output.put_line('Hola Quique'); <=== "muestra el texto por pantalla" (nótese las comillas)
4 end;
5 / hola PL/SQL procedure successfully completed.
SQL>
Ahora, la incognita errónea que siempre nos preguntamos o al menos yo lo hice es, cómo implementamos la instrucción "set serveroutput on" desde Pro*C, si este es un comando de sqlplus? Y ete aquí que lo que está mal formulada es la pregunta o el concepto del put_line. put_line no muestra un texto, sino que pone un texto dentro del buffer habilitado con enable, entonces ahora pensando que tenemos un almacen de textos en memoria, lo que nos queda es recuperarlo de ese almacen, y si alguna vez se te dá por leer los manuales de PL/SQL, vas a ver que el package dbms_output tiene varias rutinas, entre ellas el bendito get_line(), quien se encarga de obtener ese texto del buffer! Entonces ahora sí estoy en condiciones de utilizar el dbms_output desde Pro*C! Acá va el ejemplo:
exec sql begin declare section;
varchar vcTexto[40000];
short indTexto;
int iStat;
short indStat;
exec sql end declare section;
...
memset(&vcTexto, (int)NULL, sizeof(vcTexto));
exec sql execute
begin
dbms_output.enable(null);
dbms_output.put_line('Hola mundo desde PL/SQL');
dbms_output.get_line(:vcTexto:indTexto, :iStat:indStat);
end;
end-exec;
if(indTexto==0) printf("%s\n", vcTexto.arr);
Otro ejemplo (en este recupero el texto en otro bloque, pero como la sesion es la misma, el buffer prevalece y por ende su contenido):
exec sql begin declare section;
varchar vcTexto[40000];
short indTexto;
int iStat;
short indStat;
exec sql end declare section;
...
exec sql execute
begin
dbms_output.enable(null);
dbms_output.put_line('Hola mundo desde PL/SQL');
end-exec;
memset(&vcTexto, (int)NULL, sizeof(vcTexto));
exec sql execute
begin
dbms_output.get_line(:vcTexto:indTexto, :iStat:indStat);
end;
end-exec;
if(indTexto==0) printf("%s\n", vcTexto.arr);
Tercer y último ejemplo:
Dentro de una rutina almacenada, lo lleno de mensajes en todas las posibles salidas de error/exception.
SQL> create or replace procedure Quique is
2 begin
3 FOR i IN 1..100 LOOP
4 dbms_output.put_line(RPAD('*',1000,'*'));
5 END LOOP;
6 end;
7 /
Procedure created.
SQL>
e invoco la rutina desde el Pro*C, de esta forma:
exec sql begin declare section;
varchar vcTexto[40000];
short indTexto;
int iStat;
short indStat;
exec sql end declare section;
...
memset(&vcTexto, (int)NULL, sizeof(vcTexto));
exec sql execute
begin
dbms_output.enable(null);
Quique;
end;
end-exec;
while(iStat==0) {
memset(&vcTexto, (int)NULL, sizeof(vcTexto));
exec sql execute
begin
dbms_output.get_line(:vcTexto:indTexto, :iStat:indStat);
end;
end-exec;
if(indStat<0) istat = 1;
if(indTexto==0)
printf("%s\n", vcTexto.arr);
}
Cuando el buffer quede vacío, iStat contendrá el valor uno.
Cómo dice el manual, hay que declarar una variable huesped de tipo varchar no inferior a 32767, de lo contrario emitirá el error ora-6502.
Ojo! Si entre lecturas del buffer con get_line, se invoca un put_line, éste vacía el buffer con lo cual se pierde el resto de las lecturas previas al put_line.
http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_output.htm#BABGBACJ
lunes, 13 de julio de 2009
ORACLE: dbca & netca no arrancan...
...googleando encontré la respuesta!
Agregando esta línea al listener.ora se solucionó mi problema:
(ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP(HOST=hostname)(PORT = 1521))
Anteriormente, lo solucionaba renombrando el archivo, y restaurándolo posteriormente a haber utilizado alguno de los asistentes.
Queda pendiente conocer la causa de este problema!
Agregando esta línea al listener.ora se solucionó mi problema:
(ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP(HOST=hostname)(PORT = 1521))
Anteriormente, lo solucionaba renombrando el archivo, y restaurándolo posteriormente a haber utilizado alguno de los asistentes.
Queda pendiente conocer la causa de este problema!
ORACLE: Creando una instancia de base de datos a mano.
Siempre es más sencillo y rápido utilizar el asistente (dbca) para contruir una instancia de base de datos, pero a su vez comienza a crecer la incertidumbre de "qué es lo que está haciendo por atrás". Entonces, me tomé el tiempo de seguir el instructivo de los propios manuales de Oracle en inglés, y me lancé a contruirla manualmente. Aunque como dije están los manuales de Oracle explicando paso a paso como hacerlo, lo está en inglés, así que para facilitarles un poco la vida a los hispanoparlantes como yo, voy a intentar aclarar un poco cuales son estos pasos.
- Especificar a través de la variable de ambiente ORACLE_SID el nombre de la instancia que vamos a construir. En mi caso, export ORACLE_SID=xyz
- Asegurarse de que las variables de ambiente requeridas por Oracle, se encuentren definidas: ORACLE_SID, ORACLE_HOME y que la variable PATH contenga a $ORACLE_HOME/bin.
(Paso: 2)
- Es MUY IMPORTANTE seleccionar el método de autenticación para el/los administradores. Existen dos alternativas: archivos de contraseñas y a través del sistema operativo. En mi caso, utilicé el archivo de contraseñas. Este archivo lo generé con el comando orapwd, posicionado en el directorio dbs. Sin este archivo, los usuarios privilegiados como SYS, no pueden conectarse a través de TNS.
(Paso: 3)
(ANEXO: pasos para construir el archivo de contraseñas)
- Construir el archivo de parámetros de inicialización (init.ora). Se puede utilizar una plantilla que se encuentra ubicada en $ORACLE_HOME/dbs/init.ora. Se copia y se parametriza a gusto. Cada uno de los parámetros se puede visualizar en este manual de referencia.
(Paso: 4)
- Conectarse a lo que va a ser nuestra nueva instancia de base de datos. Estando conectado con el usuario unix propietario del software de base de datos, se puede conectar usando "sqlplus / as sysdba".
(Paso: 6 (el 5to paso lo obvié, porque es para bases en windows.))
- Una vez conectados, procedemos a construir el archivo de parámetros del servidor. Esto lo hacemos con la instrucción "create spfile from pfile='/.../initxyz.ora';", reemplazando [...] por la ruta absoluta donde se encuentra nuestra copia.
(Paso: 7)
- Arrancamos la instancia, sin montar la base con la instrucción: "startup nomount".
(Paso: 8)
- Construir la configuración de base de datos, con la instrucción "create database ...". En la descripción en inglés se muestra un ejemplo de la instrucción.
(Paso: 9)
- Construir el diccionario de base de datos. En el directorio $ORACLE_HOME/rdbms/admin se encuentran los script de administración, entre ellos hay que ejecutar dos: catalog.sql y catproc.sql
(Paso: 11 (el paso 10, habla sobre como contruir tablespaces adicionales.))
Repito: si quieren conectarse de esta forma: "sqlplus sys/pass@tns as sysdba" deberán tener generado el archivo de contraseñas!
Cualquier tipo de feedback sobre este artículo o cualquiera de los otros, será bienvenido.
miércoles, 10 de junio de 2009
ORACLE: Instalación del cliente Oracle 10.2.0.1 sobre Fedora 9 de 64 bits
Prerequisitos:
yum install libXp-1.0.0-11.fc9.i386
yum install libXt-1.0.4-5.fc9.i386
yum install libXtst-1.0.3-3.fc9.i386
export ORACLE_HOME=$ORACLE_BASE/product/10.2.0.1
Editar el archivo redhat-release con el siguiente contenido:
redhat release 4
Descargar el instalador desde el sitio de OTN.
Descomprimirlo: gunzip 10201_client_linux_x86_64.cpio.gz
Desempaquetarlo: cpio -idmv < 10201_client_linux_x86_64.cpio
Iniciar la instalación con el usuario oracle de unix:
./runInstaller &
yum install libXp-1.0.0-11.fc9.i386
yum install libXt-1.0.4-5.fc9.i386
yum install libXtst-1.0.3-3.fc9.i386
export ORACLE_HOME=$ORACLE_BASE/product/10.2.0.1
Editar el archivo redhat-release con el siguiente contenido:
redhat release 4
Descargar el instalador desde el sitio de OTN.
Descomprimirlo: gunzip 10201_client_linux_x86_64.cpio.gz
Desempaquetarlo: cpio -idmv < 10201_client_linux_x86_64.cpio
Iniciar la instalación con el usuario oracle de unix:
./runInstaller &
Suscribirse a:
Entradas (Atom)