Hace algunos días empece a recibir errores extraños en una de nuestras aplicaciones. Ocasionalmente nos reportaban que no podian hacer algo o que no se mostraba cierta información, pero cuando volvían a probar la aplicacion empezaba a funcionar correctamnete.
El problema con este tipo de reportes, es que son bastante difíciles de encontrar y de replicar, por consiguiente se empiezan a volver difíciles de resolver.
La aplicación es una aplicación web en java que consulta una base de datos oracle, ambos servidores estan corriendo sobre windows.
Lo primero que hicimos fue empezar a generar logs adicionales a los bloques de codigo que pensabamos pudieran estar fallando, empezamos a encontrar errores de este tipo desde mis programas:
java.sql.SQLException: ORA-04030: out of process memory when trying to allocate 123404 bytes (QERHJ hash-joi,kllcqas:kllsltba)
y desde el sistema operativo empece a ver errores en el event viewer que decían que no se podía asignar memoria a un thread de la base de datos.
Aclaro que no soy DBA, soy desarrollador. Pero a veces como desarrollador es necesario involucrase en temas de infraestructura para poder identificar los problemas que suceden.
Tenía una maquina con 4gb de ram y cuando miraba la memoria de la maquina no pasaba de los 2gb.
Encontramos 2 temas que estaban causando el problema:
1. El servidor es un windows de 32 bits, y por ser un windows de 32 bits no puedo tener ningún proceso en ejecución con mas de 2gb de uso de memoria.
Se modifico el boot.ini del servidor para que pudieran utilizarse hasta 3 gb de ram en un solo proceso.
http://technet.microsoft.com/es-es/library/bb124810.aspx
2. Revisando los parámetros de la base de datos, encontré que se tenía configurado un SGA de 2GB y un PGA de 1.6GB. Por lo que el tamaño del proceso que estaría ejecutando el oracle llegaría a tener hasta 3.6 GB en memoria. Procedímos a cambiar los parámetros de configuracion de la base de datos para corregir el tema.
Este cambio se hizó en los parámetros, sga_target y pga_aggregate_target.
saludos!
Mostrando las entradas con la etiqueta oracle 10g. Mostrar todas las entradas
Mostrando las entradas con la etiqueta oracle 10g. Mostrar todas las entradas
miércoles, agosto 26, 2009
miércoles, mayo 27, 2009
Oracle busquedas like (fuzzy, contains, soundex)
Necesito hacer una busqueda por nombres, pero quiero que el sistema me diga si hay un nombre "parecido" en el sistema. Es decir, quiero buscar un cliente llamado Carlos Castañeda pero en la base de datos tengo varios similares, aunque ninguno igual:
Juan Carlos Castañeda
Carlos Castañeda Perez
Carlos Castaneda
La verdad estuve divagando bastante en el tema y no lograba encontrar el camino correcto.
Lo primero que busqué fue la funcion Soundex. Soundex es un algoritmo que hace equivalencias foneticas de 2 palabras. Por ejemplo ait con eight. Cada palabra tiene un valor soundex y si los valores son iguales, entonces, tengo un acierto.
select soundex('eigt'), soundex('eight') from dual
Ambos registros me devuelven E230 por lo que deben ser equivalentes.
Pero.... este algoritmo solo funciona en ingles. No para español.
Seguí buscando y encontre un blog con una implementacion plsql del soundex: http://oraclenotepad.blogspot.com/2008/03/soundex-en-espaol.html
Pero el soundex me compara solamente una palabra y yo quería comparar 2 nombres completos. Modifiqué un poco el codigo e hize una funcion que sacaba el soundex de cada palabra del nombre_a_buscar en el campo_nombre y si cumplía mas del N porciento entonces devolvía ok. Estaba bien, pero...
el performance se fue al suelo cuando quería buscar en una tabla con mas de medio millon de registros.
De dedique entonces a buscar la funcion CONTAINS de Oracle. Esta funcion me permite buscar en textos grandes. Separa las palabras de un texto y las indexa. Hay que crear un indice para utilizarla:
create index clientes_idx on temp (nombre) indextype;
ya ahi podía hacer consultas:
SELECT score(1),nombre FROM clientesWHERE CONTAINS (nombre, 'castañeda',1) > 0;
El contains devuelve un score con el que se evalúa el resultado. Mientras mas alto sea el resultado es mas exacta la busqueda.
Cuando busco con 2 nombres, este query me devuelve los resultados que tengan los 2 nombres, por ejemplo juan Carlos Castañeda o Carlos Castañeda Perez
SELECT score(1),nombre FROM clientesWHERE CONTAINS (nombre, 'carlos castañeda',1) > 0;
pero... no me devuelve nombres como Carlos Alberto Castañeda Perez.
agregué un OR a la consulta
SELECT score(1),nombre FROM clientesWHERE CONTAINS (nombre, 'carlos or castañeda',1) > 0;
pero... me devuelve todos los carlos y todos los castañedas. Carlos Perez, Carlos Lopez, Juan Castañeda, Carlos Castañeda, etc.
Cambié la consulta a un AND y mejoró
SELECT score(1),nombre FROM clientesWHERE CONTAINS (nombre, 'carlos or castañeda',1) > 0;
Pero me posicionaba de igual manera el Carlos Castañeda del Carlos Jose Castañeda y del Carlos Castañeda Perez.
Necesitaba diferenciar las busquedas exactas.
Busque entonces:
SELECT score(1),nombre FROM clientesWHERE CONTAINS (nombre, 'carlos or castañeda or (carlos and castaneda)',1) > 0;
El query se empezaba a complicar un poco. Además estaba buscando tambien que me diera busquedas Fuzzy, es decir, busquedas que me devolvieran palabras que contienen "casi" todos los caracteres de la palabra a buscar.
en ese caso debía buscar
SELECT score(1),nombre FROM clientesWHERE CONTAINS (nombre, '?carlos or ?castañeda',1) > 0;
Encontré también algo que no había utilizado que es el "query template" que me permitiría tener un query un poco más sencillo, con esto deje mi query así:

Lo que hace la plantilla es partir la cadena que envio en textquery como si fuesen varios tokens, y además va evaluando progresivamente cada una de las opciones que le envío. Es decir, primero busca con AND para ver si estan todas las palabras:
transform((TOKENS, "{", "}", "AND"))
Luego busco con AND pero con palabras "fuzzy" o parecidas, añadiendo el "?"
transform((TOKENS, "?{", "}", "AND"))
Si quisiera que hiciera un soundex pondria un "!" antes del token. Pero el soundex es en ingles y no me sirve.
transform((TOKENS, "!{", "}", "AND"))
Luego hago lo mismo pero con OR para que busque alguna de las 2 palabras.
pero...
también estuve leyendo que el query no estaba sincronizado por default, habría que sincronizarlo.
http://hugoracle.blogspot.com/2008/07/mejora-de-desempeo-con-oracle-text.html
http://www.orafaq.com/forum/t/95509/2/
http://www.oracle.com/technology/products/text/pdf/10gtext_features_overview.pdf
http://www.oracle.com/technology/products/text/htdocs/prog_relax.html?_template=/ocom/print
Juan Carlos Castañeda
Carlos Castañeda Perez
Carlos Castaneda
La verdad estuve divagando bastante en el tema y no lograba encontrar el camino correcto.
Lo primero que busqué fue la funcion Soundex. Soundex es un algoritmo que hace equivalencias foneticas de 2 palabras. Por ejemplo ait con eight. Cada palabra tiene un valor soundex y si los valores son iguales, entonces, tengo un acierto.
select soundex('eigt'), soundex('eight') from dual
Ambos registros me devuelven E230 por lo que deben ser equivalentes.
Pero.... este algoritmo solo funciona en ingles. No para español.
Seguí buscando y encontre un blog con una implementacion plsql del soundex: http://oraclenotepad.blogspot.com/2008/03/soundex-en-espaol.html
Pero el soundex me compara solamente una palabra y yo quería comparar 2 nombres completos. Modifiqué un poco el codigo e hize una funcion que sacaba el soundex de cada palabra del nombre_a_buscar en el campo_nombre y si cumplía mas del N porciento entonces devolvía ok. Estaba bien, pero...
el performance se fue al suelo cuando quería buscar en una tabla con mas de medio millon de registros.
De dedique entonces a buscar la funcion CONTAINS de Oracle. Esta funcion me permite buscar en textos grandes. Separa las palabras de un texto y las indexa. Hay que crear un indice para utilizarla:
create index clientes_idx on temp (nombre) indextype;
ya ahi podía hacer consultas:
SELECT score(1),nombre FROM clientesWHERE CONTAINS (nombre, 'castañeda',1) > 0;
El contains devuelve un score con el que se evalúa el resultado. Mientras mas alto sea el resultado es mas exacta la busqueda.
Cuando busco con 2 nombres, este query me devuelve los resultados que tengan los 2 nombres, por ejemplo juan Carlos Castañeda o Carlos Castañeda Perez
SELECT score(1),nombre FROM clientesWHERE CONTAINS (nombre, 'carlos castañeda',1) > 0;
pero... no me devuelve nombres como Carlos Alberto Castañeda Perez.
agregué un OR a la consulta
SELECT score(1),nombre FROM clientesWHERE CONTAINS (nombre, 'carlos or castañeda',1) > 0;
pero... me devuelve todos los carlos y todos los castañedas. Carlos Perez, Carlos Lopez, Juan Castañeda, Carlos Castañeda, etc.
Cambié la consulta a un AND y mejoró
SELECT score(1),nombre FROM clientesWHERE CONTAINS (nombre, 'carlos or castañeda',1) > 0;
Pero me posicionaba de igual manera el Carlos Castañeda del Carlos Jose Castañeda y del Carlos Castañeda Perez.
Necesitaba diferenciar las busquedas exactas.
Busque entonces:
SELECT score(1),nombre FROM clientesWHERE CONTAINS (nombre, 'carlos or castañeda or (carlos and castaneda)',1) > 0;
El query se empezaba a complicar un poco. Además estaba buscando tambien que me diera busquedas Fuzzy, es decir, busquedas que me devolvieran palabras que contienen "casi" todos los caracteres de la palabra a buscar.
en ese caso debía buscar
SELECT score(1),nombre FROM clientesWHERE CONTAINS (nombre, '?carlos or ?castañeda',1) > 0;
Encontré también algo que no había utilizado que es el "query template" que me permitiría tener un query un poco más sencillo, con esto deje mi query así:

Lo que hace la plantilla es partir la cadena que envio en textquery como si fuesen varios tokens, y además va evaluando progresivamente cada una de las opciones que le envío. Es decir, primero busca con AND para ver si estan todas las palabras:
Luego busco con AND pero con palabras "fuzzy" o parecidas, añadiendo el "?"
Si quisiera que hiciera un soundex pondria un "!" antes del token. Pero el soundex es en ingles y no me sirve.
Luego hago lo mismo pero con OR para que busque alguna de las 2 palabras.
pero...
también estuve leyendo que el query no estaba sincronizado por default, habría que sincronizarlo.
beginAlgunos de los links que leí... solo algunos:
CTX_DDL.SYNC_INDEX('clientes_idx','50K');
end;
/
pero.. yo no quería sincronizarlo cada ves que ejecuto el query... así que cambie el indice para que se sincronice al hacer commit:
create index clientes_idx on temp (nombre) indextype is ctxsys.context parameters('sync (on commit)');
ahora sí, cuando quise buscar CASTANEDA o JOSE en lugar de josé no me devolvia los mismo valores. Consideras las tildes como caracteres distintos.
Encontre que el indice hay que indicarle que utilice un LEXER_BASIC.
Para esto me conecte como sys y me di grants: grant execute on CTX_DDL to scott;
ya en mi esquema, creé una preferencia con el LEXER que necesito:
begin
CTX_DDL.CREATE_PREFERENCE ('LEXER_SINTILDES', 'BASIC_LEXER');
CTX_DDL.SET_ATTRIBUTE ('LEXER_SINTILDES', 'BASE_LETTER', 'YES');
end;
/
recreé el indice:
create index temp_nombre_idx on temp (nom_contacto) indextype is ctxsys.context parameters('sync (on commit) LEXER LEXER_SINTILDES');
Con eso ya logré los resultados que esperaba. mmm... no del todo. No encontré un soundex que me diera mejores resultados sin sacrificar el performance. Pero tengo buenos resultados.
saludos!
http://hugoracle.blogspot.com/2008/07/mejora-de-desempeo-con-oracle-text.html
http://www.orafaq.com/forum/t/95509/2/
http://www.oracle.com/technology/products/text/pdf/10gtext_features_overview.
http://www.oracle.com/technology/products/text/htdocs/prog_relax.html?_template=/ocom/print
Etiquetas:
Contains,
Fuzzy,
oracle 10g,
Soundex
lunes, marzo 23, 2009
Error ORA-27102 al modificar el sga_max_size en oracle
El sabado me topé con un error en una base de datos. Un error que me complicó un poco más de la cuenta.
Necesitabamos modificar los parámetros de memoria asignada al SGA de una base de datos. Lo que hicieron fue modificar el sga_max_size de Oracle para que consumiera más memoria de la que se tenía.
El problema fue que luego de hecho el cambio y reiniciada la base de datos, la misma no levantaba.
Revisando logs encontré que me daba un mensaje:
ORA-27102: Out of memory
OSD-00022: aditional error information
O/S-Error: (OS 8) Not enough storage avaible
Resulta que la maquina donde estaba instalado el oracle era un nodo de un VMWARE y al tratar de asignar la memoria no se encontró espacio de memoria suficiente.
Hasta aca todo normal, sería solo de modificar de nuevo los parámetros y reiniciar.
Ingrese al sqlplus:
sqlplus /nolog
connect / as sysdba
trate de subir el pfile al spfile y levantar la base de datos:
CREATE spfile FROM pfile='c:/initORCL.ora';
startup
Y me dio un error:
ORA-27100 shared memory realm already exists
mmm.... la base esta levantada? probe bajarla
shutdown immediate
ORA-27101 shared memory realm does not exists
Y entonces.. ni esta arriba ni esta abajo ???! Buscando en internet encontre un par de paginas que habia una especie de bug de oracle que te dejaba la base de datos asi...
Que hice?
* baje el servicio de oracle
* baje la base con linea de comando oradim -shutdown -sid ORCL -shuttype srvc,inst
* me conecte al sqlplus
* sqlplus /nolog
* connect / as sysdba
* Cambie el pfile
* CREATE spfile FROM pfile='c:/initORCL.ora';
* Levante la base usando el nuevo pfile
*
oradim -startup -sid ORCL -starttype srvc -pfile c:/initORCL.ora
Ahi ya me pude conectar.. pero la base no levantaba automaticamente. Lo siguiente es lo que creo que hay que hacer.. pero no quise hacerlo porque ya eran las 4:00am... y debiamos estar con la base levantada en produccion.. (ohh... fue en una base de datos en produccion).-
* Borrar el servicio de oracle oradim -delete -sid ORCL
* Recrear el servicio de oracle oradim -new -sid ORCL -pfile c:/initORCL.ora
y ya....
Saludos!
Ref.
http://www.dba-oracle.com/t_ora_27100_shared_memory_realm_already_exists.htm
http://newsgroups.derkeiler.com/Archive/Comp/comp.databases.oracle.server/2005-10/msg01447.html
Necesitabamos modificar los parámetros de memoria asignada al SGA de una base de datos. Lo que hicieron fue modificar el sga_max_size de Oracle para que consumiera más memoria de la que se tenía.
El problema fue que luego de hecho el cambio y reiniciada la base de datos, la misma no levantaba.
Revisando logs encontré que me daba un mensaje:
ORA-27102: Out of memory
OSD-00022: aditional error information
O/S-Error: (OS 8) Not enough storage avaible
Resulta que la maquina donde estaba instalado el oracle era un nodo de un VMWARE y al tratar de asignar la memoria no se encontró espacio de memoria suficiente.
Hasta aca todo normal, sería solo de modificar de nuevo los parámetros y reiniciar.
Ingrese al sqlplus:
sqlplus /nolog
connect / as sysdba
trate de subir el pfile al spfile y levantar la base de datos:
CREATE spfile FROM pfile='c:/initORCL.ora';
startup
Y me dio un error:
ORA-27100 shared memory realm already exists
mmm.... la base esta levantada? probe bajarla
shutdown immediate
ORA-27101 shared memory realm does not exists
Y entonces.. ni esta arriba ni esta abajo ???! Buscando en internet encontre un par de paginas que habia una especie de bug de oracle que te dejaba la base de datos asi...
Que hice?
* baje el servicio de oracle
* baje la base con linea de comando oradim -shutdown -sid ORCL -shuttype srvc,inst
* me conecte al sqlplus
* sqlplus /nolog
* connect / as sysdba
* Cambie el pfile
* CREATE spfile FROM pfile='c:/initORCL.ora';
* Levante la base usando el nuevo pfile
*
oradim -startup -sid ORCL -starttype srvc -pfile c:/initORCL.ora
Ahi ya me pude conectar.. pero la base no levantaba automaticamente. Lo siguiente es lo que creo que hay que hacer.. pero no quise hacerlo porque ya eran las 4:00am... y debiamos estar con la base levantada en produccion.. (ohh... fue en una base de datos en produccion).-
* Borrar el servicio de oracle oradim -delete -sid ORCL
* Recrear el servicio de oracle oradim -new -sid ORCL -pfile c:/initORCL.ora
y ya....
Saludos!
Ref.
http://www.dba-oracle.com/t_ora_27100_shared_memory_realm_already_exists.htm
http://newsgroups.derkeiler.com/Archive/Comp/comp.databases.oracle.server/2005-10/msg01447.html
Etiquetas:
ora-27102,
oracle 10g,
oradim,
sga_max_size
Suscribirse a:
Entradas (Atom)
