Error de Oracle ORA-12705 (Cannot access NLS data files or invalid environment specified)

Hay veces que al conectarnos a una base Oracle, nos retorna un error ORA-12705 con el mensaje “ORA-12705:Cannot access NLS data files or invalid environment specified”, o en un ambiente en español “ORA-12705: No se puede acceder a los archivos de datos NLS o se ha especificado un entorno no válido”.

Un stack trace típico de este error en una aplicación Java es algo parecido a esto:

Caused by: java.sql.SQLException: ORA-00604: error occurred at recursive SQL level 1
ORA-12705: Cannot access NLS data files or invalid environment specified
	at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112)
	at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:331)
	at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:283)
	at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:278)
	at oracle.jdbc.driver.T4CTTIoauthenticate.receiveOauth(T4CTTIoauthenticate.java:785)
	at oracle.jdbc.driver.
T4CConnection.logon(T4CConnection.java:362)
	at oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java:414)
	at oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:165)
	at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:35)
	at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:801)
	at java.sql.DriverManager.getConnection(DriverManager.java:582)
	at java.sql.DriverManager.getConnection(DriverManager.java:185)
	at org.apache.commons.dbcp.DriverManagerConnectionFactory.createConnection(DriverManagerConnectionFactory.java:65)
	at org.apache.commons.dbcp.PoolableConnectionFactory.makeObject(PoolableConnectionFactory.java:294)
	at org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:840)
	at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:96)
	... 7 more

O algo parecido a esto, en español:

ORA-12705: No se puede acceder a los archivos de datos NLS o se ha especificado un entorno no válido); nested exception is org.apache.commons.dbcp.SQLNestedException: Cannot create PoolableConnectionFactory (ORA-00604: se ha producido un error a nivel 1 de SQL recursivo ORA-12705: No se puede acceder a los archivos de datos NLS o se ha especificado un entorno no válido)

En mi caso, el problema se da cuando tengo el sistema operativo -y el conjunto de caracteres- configurado para Uruguay. Para solucionarlo en las aplicaciones Java, podemos agregar opciones para configurar el locale que queremos que la JVM utilice, de forma que no tome el del sistema operativo. Esto se hace agregando las siguientes opciones al ejecutar el comando java:

-Duser.region=us -Duser.language=en

Con user.region configurada para ‘us’ y user.language para ‘en’ no falla, eso es seguro. La configuración para México (-Duser.region=mx -Duser.language=es) o España (-Duser.region=es -Duser.
language=es) también funciona bien.

Otra opción es setear la variable de entorno NLS_LANG con un valor de tres partes: _.. Ejemplos de NLS_LANG pueden ser “AMERICAN_AMERICA.WE8ISO8859P1” o “AMERICAN_AMERICA.UTF8”. Podemos ver todos los valores válidos para el lenguaje, territorio y conjunto de caracteres en la vista llamada V$NLS_VALID_VALUES, mediante la consulta

SELECT parameter, value FROM V$NLS_VALID_VALUES

Una tercer opción, válida en Windows es cambiar la configuración regional y de idioma para algún país que Oracle soporte (Estados Unidos, España, México, etc.). Hay que tener en cuenta sin embargo que esta configuración nos puede afectar otros programas, especialmente en la configuración de moneda, formato de fecha o de separación de miles.

Los siguientes links tienen buena información al respecto, aunque no muy orientadas a resolver el problema para lenguajes o sets de caractedes “raros” para Oracle:
http://ora-12705.ora-code.com/
http://www.dba-oracle.com/t_nls_lang.htm
http://www.dba-oracle.com/t_ora_12705_error.htm
http://oraclespin.wordpress.com/2008/05/01/setting-nls_lang-for-oracle/

Tests de performance y de stress

Introducción

Los tests de performance son aquellos que sirven para determinar qué tan rápido o qué tan bien se comporta un sistema sometido a una carga en particular. También pueden ser utilizados para validar y verificar otros requerimientos no funcionales del sistema como ser estabilidad, escalabilidad, disponibilidad o consumo de recursos.

Los tests de performance pueden buscar diferentes objetivos. Pueden servir para demostrar que un sistema cumple con determinado criterio de aceptación, para comparar dos sistemas y determinar cuál se comporta mejor o bien para detectar qué sistema externo o qué componente interno es el cuello de botella. Para el último caso, los tests de performance se pueden utilizar junto a profilers para medir y determinar cómo se distribuye el uso de recursos (tiempo, CPU, I/O, memoria, etc.) entre los diferentes componentes del sistema.

Los tests de stress, en cambio, son tests diseñados para verificar el comportamiento de un sistema al introducir caos o incertidumbre, y el objetivo es comprobar la robustez del software cuando es sometido a condiciones diferentes a la de operación normal. Estos tests son particularmente importantes para software considerado crítico, y hacen énfasis en características como robustez, disponibilidad o manejo controlado de errores y situaciones de excepción.

Al igual que con los tests unitarios o de integración, la noción de “testear temprano y testear seguido” también aplica para los tests de performance y de stress. Es importante considerar al principio de un proyecto si se van a requerir tests de performance y/o stress (por ejemplo para cumplir requerimientos no funcionales) o qué componentes van a participar de estos tests. De forma análoga
a la detección de bugs, la detección de problemas de performance se va complicando a medida que vamos avanzando en las etapas del proyecto, y nuestro sistema está más cerca del producto final. Si bien encontrar problemas de performance en una prueba de concepto o prototipo puede llegar a determinar un cambio de arquitectura o de tecnología y consumir varias horas de retrabajo, el detectar este mismo problema luego de puesto en producción puede llegar a ser un problema de varios órdenes de magnitud peor. Sin embargo, no es tan fácil poder contar con un ambiente, con los sistemas externos -o procesos que los simulen- y con los datos necesarios, pero es importante establecer si va a ser posible y en qué momento se realizarán.

Este post estará mayormente centrado en los tests de performance, pero varios de los puntos destacados aplican también a la hora de planificar los tests de stress.

Objetivos

Como comentábamos en la introducción, los tests de performance pueden perseguir diferentes objetivos.
Es importante delinear estos objetivos al diseñar los tests, así como también los parámetros fijos y variables con los que se ejecutarán. Por ejemplo, si imaginamos que queremos determinar la capacidad máxima de respuestas por segundo de un web service, no es lo mismo realizar las pruebas con 3 clientes concurrentes que con 3000 clientes concurrentes. Se debe conocer de antemano a la realización de los tests en qué aspectos debemos enfocarnos, y con qué parámetros analizaremos esos aspectos.

Algunos objetivos posibles a perseguir pueden ser:

Cumplir con requerimientos no funcionales

Además de la definición de requerimientos funcionales (por ejemplo en forma de casos de uso), un sistema se pueden definir también con requerimientos que son ortogonales a los funcionales. Ejemplos típicos de estos requerimientos no funcionales pueden ser seguridad, escalabilidad, volumen de datos a manejar o niveles mínimos aceptables de performance.

El cumplimiento o no de algunos requerimientos no
funcionales se puede determinar en función del resultado de tests de performance, si se diseñan para comprobar que el sistema cumple con los criterios establecidos.

Conocer nuestro sistema

Un test de performance puede ser utilizado para conocer cuánto podemos esperar de nuestro sistema para un aspecto determinado. Volviendo al caso del web service, si bien puede que no haya requerimientos no funcionales acerca de la cantidad máxima de requests por segundo, puede llegar a interesarnos el conocer su límite, para tenerlo en cuenta luego en un monitoreo en producción. Por supuesto, que este tipo de test de performance debe ser realizado en un ambiente (hardware, software, datos) lo más parecido posible al real.

También puede ser interesante determinar cuál es el aspecto limitante, y que este conocimiento nos ayude en un futuro dimensionamiento de sistemas similares.

Profiling

Si pensamos en hacer tests de performance utilizando además herramientas de profiling,
podremos pensar en encontrar cuellos de botella de nuestro sistema. Una sesión de profiling puede ser tan simple como registrar estadísticas en un log y analizarlas a mano o tan complejas como el uso de herramientas especialmente construidas para este fin. Un ejemplo de dichas herramientas para el caso del lenguaje Java puede ser el excelente JProfiler, que permite monitorear el tiempo usado por cada método, clase, paquete e inclusive invocaciones JDBC o JMS. También permite monitorear el uso de memoria en los diferentes heaps, garbage collection o cantidad de instancias por clase.

Para el uso de herramientas de profiling generalmente es necesario generar en el sistema una carga de trabajo que simule su uso en la vida real. Acá es donde los tests de performance entran en juego, combinándose una herramienta que sepa generar la carga, y otro que sepa analizar el funcionamiento de nuestro sistema.

Cabe
destacar que la performance de nuestro sistema es muy inferior cuando la herramienta de profiling la monitorea, pero los recursos consumidos deberían ser proporcionales a los reales.

Comparación entre sistemas

Los tests de performance y de stress pueden servir para conocer y optimizar nuestro sistema, pero también pueden servir para comparar dos o más sistemas similares, y determinar cuál de ellos es superior en algún aspecto que nos interese comparar.

Un ejemplo de esto puede ser la comparación entre dos implementaciones de una misma funcionalidad. Otro posible podría ser la medición de performance de dos motores de base de datos diferentes. Es más, podemos querer determinar cómo se comporta un mismo sistema en distintos ambientes, haciendo cambios en el hardware o en el software de base (por ejemplo sistema operativo) y descubrir cómo impactan estos cambios en la performance de nuestro sistema.

Objetos

La lista de objetos o sistemas a los que podemos realizarles tests de
performance y de stress es demasiado amplia para detallarla en su totalidad. A modo de ejemplo, algunos de los sistemas objeto de los tests pueden ser:

  • Bases de datos, stored procedures, consultas SQL
  • Web services
  • Sitios y servidores web
  • Servidores FTP
  • Colas de mensajes (MQs)
  • Sistemas que interactúan directamente utilizando mediante conexiones TCP/IP

Tipos de tests de stress

Como comentamos al principio, los tests de stress o de performance pueden apuntar a aspectos bien diferentes de un sistema. Repasemos cuáles de estos aspectos nos pueden interesar.

Concurrencia

En sistemas de tipo servidor, siempre es importante comprobar que para un sistema es posible procesar correctamente la carga de invocaciones de sus clientes. En general, esta carga es medida en función de la cantidad de pedidos que es capaz de contestar por unidad de tiempo (medida en TPS – transacciones por segundo) y en función de la cantidad de
clientes concurrentes que le realizan esos pedidos. En la gran mayoría de los casos estas dos variables no son independientes.

Tiempo de respuesta

De la mano de las TPS para una determinada cantidad de clientes viene el tiempo requerido para procesar cada invocación. Generalmente este tiempo de respuesta crece cuando se crece la cantidad de clientes o la cantidad de TPS generadas por cada cliente. La rapidez con la que crece el tiempo de respuesta determinará -de forma inversamente proporcional- la escalabilidad de nuestro sistema.

Generalmente es uno de los requerimientos no funcionales de sistemas cliente-servidor o servidor, e impacta directamente en la agilidad percibida por el usuario final. Es necesario definir y verificar los requerimientos mínimos determinando de antemano el ambiente y un perfil de uso.

De resistencia (endurance testing)

Los tests de resistencia generalmente se realizan para determinar o comprobar que un sistema puede funcionar cierto tiempo con la carga esperada. En estos tests pueden surgir problemas de degradación de performance o resource leaks (memoria RAM, handles de archivos, conexiones abiertas, etc.). También –especialmente en sistemas con alta concurrencia– pueden ser útiles para detectar deadlocks, situaciones de por si bastante complicadas de diagnosticar y solucionar.

Límite del sistema (break point)

El encontrar el límite o break point de un sistema implica exigirlo hasta tal punto que ya no sea capaz de responder como debería. Para simular escenarios de stress extremo podemos optar por exigir al sistema de forma superior para la cual fue diseñado, o también tenemos la opción de destinar menos recursos de los previstos para el sistema: que esté en un servidor con el CPU ya ocupado, configurar el uso de memoria máximo permitido a menos de lo mínimo aconsejable, utilizar dispositivos de almacenamiento lentos, etc.

nSi bien no es esperado que el sistema procese de forma correcta todas las peticiones, con este tipo de tests podemos comprobar que el sistema se comportará de una manera aceptable (sin corromper datos o dejar recursos inutilizables).

A tener en cuenta

Existen varias consideraciones que, si no se tienen en cuenta pueden hacer que los tests de performance o de stress no ayuden a diagnosticar problemas, o que nos lleven camino a solucionar problemas que no existen.

Algunos de estos puntos son:

  • Repetibilidad: generalmente los tests de performance implicarán varios ciclos de correr el test, evaluar los resultados, hace algún cambio, y correr el test nuevamente. Es deseable tener un ambiente en el cual los tests se puedan repetir sin sufrir cambios en los resultados.
  • Se deberá recrear el ambiente de forma lo más similar posible para cada ronda. Se debe tener en cuenta que los arranques en frío (cold startup), caching, estado de los sistemas externos, etc. pueden
    afectar el resultado de los tests. Por ejemplo, un sistema que utilice una base de datos puede no tener inicializado su pool de conexiones a la base de datos en la primera ejecución del test, y esto hará que el primer ciclo de pruebas difiera en resultados del segundo y posteriores. Deberán ser consideradas técnicas de “calentamiento” del sistema, o correr los tests de cada ciclo partiendo del estado inicial.
  • Como consideración adicional a los puntos anteriores, puede ser deseable construir mocks (simuladores) de los sistemas externos. Esto ayudará a que nuestros tests sean más repetibles, ya que nos liberamos de una dependencia a sistemas que no podemos modificar. Como punto en contra de los mocks, debemos tener claro que pueden no comportarse de manera idéntica a los sistemas originales, distorsionando los tests.
  • Code freeze: es deseable que los diferentes ciclos de tests se ejecuten partiendo del mismo código, y que los cambios realizados sean conocidos.
    Debemos evitar introducir demasiados cambios entre ciclo y ciclo, para tener claro cómo impactó cada uno de ellos.
  • Si queremos conocer datos de cómo se comportará nuestro sistema en producción, el ambiente en el que corramos los tests debe ser lo más parecido al de producción posible. Esto incluye hardware, sistema operativo, base de datos, otros sistemas, configuración, etc. A veces no es posible acceder a este tipo sistemas, ya sea por su costo o porque directamente porque hay sistemas externos que no podemos utilizar para las pruebas. Si sabemos que podemos tener un cuello de botella distinto al de producción, considerar sistemas mocks para aislarnos del mismo (ver uno de los puntos anteriores).
  • Es deseable que la distribución del juego de datos para los test sea lo más parecida posible a la realidad. Por ejemplo, si sabemos al testear una base de datos que hay un 80% de selects, un 15% de inserts y que el restante 5% son updates, deberíamos
    distribuir las invocaciones SQL de la misma manera, para que el sistema se comporte de forma semejante a la real.
  • Utilizar un determinado juego de datos puede distorsionar los resultados de los tests. Imaginemos que nuestro sistema expone un web service con un método que recupera empleados de una tabla de una base de datos. Si nuestros tests invocan siempre el método del web service con el mismo identificador de empleado, podría pasar que los datos recuperados queden cacheados y no se esté yendo a la base de datos a recuperarlos. Otro escenario podría ser que se ocasionen bloqueos entre los diferentes pedidos concurrentes. Por ejemplo, si el mismo web service sólo permite una operación concurrente por empleado. En este caso, si todos los clientes del web service envían el mismo id de empleado, la carga no será representativa de la realidad, y los resultados serán mucho peores.

Herramientas

JMeter

JMeter es un projecto open source de Apache Jakarta. Está construido 100% en Java, lo que garantiza su portabilidad entre plataformas. Permite realizar tests de performance a una variedad de tipos de sistemas (desde servlets y páginas web estáticas hasta ejecución de stored procedures de una base de datos). Permite extensiones en la forma de nuevas clases de tests, lo que permite probar prácticamente cualquier tipo de sistema con cualquier juego de datos.

Brinda además herramientas para hacer análisis gráficos de los resultados, e inclusive posibilidades de controlar una “red de esclavos JMeter” para poder correr tests masivos sin que el cliente sea el cuello de botella.

JProfiler

JProfiler es un producto comercial de ej-technologies para hacer profiling de aplicaciones en tiempo real. Puede funcionar stand-alone o integrado a los IDEs más utilizados.

Su intuitiva interfaz gráfica, la facilidad de uso y su potencial lo hacen una excelente herramienta, digna de probarla por lo menos durante los 10 días de evaluación.

Scripts manuales

No es obligatorio contar con herramientas muy complejas para crear tests de stress o de performance. En algunos casos, un buen conjunto de scripts o de programas de test y algunas líneas adicionales de log de nuestra aplicación puede servir para descubrir cuellos de botella o para comprobar el correcto cumplimiento de ciertos requerimientos no funcionales.

Referencias

Wikipedia – Software load testing

MSDN Library patterns and practices – Performance Testing Guidance for Web Applications

The art of application performance testing (libro)

Performance vs. load vs. stress testing

JMeter

JProfiler

Listado de comandos de administración de Informix

Introducción

La idea de este post es listar algunos comandos útiles para el servidor de base de datos Informix, con el que algunos tenemos que sufrir trabajar día a día. Muchos de ellos se pueden ejecutar desde ambientes gráficos, pero generalmente no disponemos de dichos ambientes en servidores de testing o producción.

Intenteré ir actualizando la lista a medida que me vaya encontrando con otros comandos que considere que valgan la pena.

Los comandos

Bajar el motor

Desde la línea de comandos, ejecutar:

onmode -ky

Podemos hacerlo de forma más “delicada”, siguiendo los siguientes pasos:

Ejecutar

onmode -sy

para dejar no permitir nuevas conexiones, pero permitir que las conexiones que ya estaban abiertas se cierren de forma normal. luego de cerrar todas las conexiones, el servidor queda en quiescent mode, algo
así como inactivo, pero no apagado.

El siguiente paso es movernos al siguiente log lógico, ejecutando:

onmode -l

Luego forzamos un checkpoint, de forma de estar seguros de escribir todos los buffers a disco:

onmode -c

Finalmente, ejecutamos el comando para dejar el servidor de Informix offline:

onmode -ky

Subir el motor

Para subir el motor de Informix, ejecutamos sin parámetros el comando:

oninit

En Linux/UNIX, debemos estar logueados como root o como informix para poder ejecutar oninit. En Windows, se debe ejecutar siendo miembro del grupo Informix-Admin.

Ver la descripción de un error

Dado un código de error, podemos obtener una descripción y posibles acciones correctivas ejecutando:

finderr numero#

El resultado es similar al siguiente (cambiando para cada error, claro está):

infordb:~ # finderr 167
-167    ISAM error: Storage-space size is not multiple of PAGESIZE.

The database server administrator sees this error. When you define a
storage space, you must specify a page size that is an integral multiple of
the system page size. The system page size is set in the Parameters
screen when the database server is first initialized.

Pasar una base de transaccional a no transaccional y viceversa

Al restaurar un respaldo de una base de datos, si no decimos explícitamente, la base restaurada no soportará transacciones, sino que quedará en modo no transaccional. Al intentar utilizarla desde nuestras aplicaciones, las sentencias de BEGIN WORK, COMMIT, ROLLBACK, etc. fallarán por estar trabajando la base en este modo.

En estos casos, podemos pasar la base de datos a transactional unbuffered ejecutando el siguiente comando en una terminal:

ontape -s -L 0 -U [database] 

nO el siguiente, para pasarla a transactional buffered:

ontape -s -L 0 -B [database]

Si por el contrario, queremos pasar una base de modo transaccional a no transaccional, ejecutamos:

ontape -s -L 0 -N [database]

Por información acerca de la diferencia los logging modes transactional unbuffered y transactional buffered, ver este otro post del blog.

Exportar una base de datos

El comando dbexport descarga todos los datos de cada tabla de una base de datos y genera un esquema de la base de datos. Para exportar una base de dato a archivos, debemos ejecutar el siguiente comando en una terminal:

dbexport [database] 

Esto generará un directorio [database].exp con los datos de cada tabla, y desplegará por salida estandar (pantalla,
al menos que se rediriga a un archivo) un script con la creación de los objetos de la base.

Importar una base de datos

Para importar una base de datos podemos ejecutar el comando dbimport. dbimport lee el archivo de esquema generado por el comando dbexport y crea una base de datos cargando los datos de los archivos. Se puede especificar un dbspace determinado, y el logging mode de la base importada:

dbimport [database] [-i directory] [-d dbspace] [-l [buffered]]  

En donde:

  • en [database].exp están ubicados los archivos de datos a importar
  • -d dbspace: especifica el nombre del dbspace en donde la base será creada. Por defecto, será rootdbs.
  • -l: Establece que la base importada funcionará en modo unbuffered transaction logging
  • -l buffered: Establece que la base importada funcionará en modo buffered transaction logging

El parámetro [database] es la ubicación
en de los archivos a importar; el comando buscará un directorio llamado [database].exp para leer los datos de las tablas. Si se especifica, se buscará ese directorio dentro de [directory]. Se asume que existirá un archivo [database].exp/[database].sql conteniendo la estructura de la base de datos (tablas, índices, contraints, etc.).

Mostrar información de uso de espacio físico

Ejecutando el siguiente comando desde una terminal, obtenemos un reporte de los diferentes dbspaces y el espacio utilizado en cada uno:

onstat -d

La salida es similar a la siguiente:

infordb:~ # onstat -d

IBM Informix Dynamic Server Version 10.00.FC7     -- On-Line -- Up 1 days 13:15:39 -- 38720 Kbytes

Dbspaces
address          number   flags      fchunk   nchunks  pgsize   flags    owner    name
450c8e78         1        0x60001    1        1        2048     N  B     Informix rootdbs
45253450         2        0x60001    2        1        2048     N 
 B     Informix datadbs
 2 active, 2047 maximum

Chunks
address          chunk/dbs     offset     size       free       bpages     flags pathname
450c9028         1      1      0          250000     58385                 PO-B  /opt/IBM/Informix/CHUNKS/rootdbs.000
45269db8         2      2      0          1048576    516245                PO-B  /opt/IBM/Informix/CHUNKS/datadbs.000
 2 active, 32766 maximum

NOTE: The values in the "size" and "free" columns for DBspace chunks are
      displayed in terms of "pgsize" of the DBspace to which they belong.

Expanded chunk capacity mode: always

El tamaño y el espacio libre de cada chunk (columnas size y free) están expresadas en páginas. El tamaño de cada página está expresada en bytes en la columna pgsize, por lo que el tamaño de cada chunk está determinado por size x pgsize. Cada chunk está asociado a un dbspace, y esta asociación se detalla en la columna chunk/dbs (el primer número es el id del chunk, el segundo es el id del dbspace).

Este reporte también muestra información de replicación, rutas en dispositivos físicos, etc. Por una descripción completa, ver la página de onstat -d en la Administrator’s Reference de Informix.

Actualizar las estadísticas

Desde dbaccess u otro cliente de Informix, podemos ejecutar los siguientes comandos para actualizar las estadísticas de la base de datos:

Actualizar estadísticas de todas las tablas la base de datos:

update statistics

Para actualizar además las estadísticas de distribución de cada tabla (es más lento):

update statistics high	

Para actualizar las estadísticas para una tabla:

UPDATE STATISTICS [HIGH] FOR TABLE [tabla]

Lock mode de las tablas

En este post escribí acerca de los lock modes de Informix. Para obtener la información acerca del tipo de bloqueo que tienen las tablas de una base podemos ejecutar la sigiuente consulta:

SELECT tabname,locklevel FROM systables WHERE tabid>99

La columna tabname contiene el nombre de la tabla, la columna locklevel contiene ‘P’ si el lock mode es por página, o ‘R’ si es por tupla.

Para crear una tabla con un lock mode determinado lo especificamos al ejecutar el comando CREATE TABLE:

CREATE TABLE customer(customer_num serial, lname char(20)...)
LOCK MODE ROW|PAGE|TABLE;

Para cambiar el lock mode de una tabla utilizamos el comando ALTER TABLE:

ALTER TABLE [tabla] MODIFY
LOCK MODE (PAGE|ROW|TABLE)

Referencias

Tagged

Lock modes de tablas de Informix

El lock mode de una tabla especifica el nivel de granularidad que se tendrá para acceder a los datos de forma concurrente. Hay 3 niveles: por tupla (row), por página (page), o por tabla (table).

Al menos que se explicite, al crear una tabla el modo de bloqueo (lock mode) será por página. Si la tabla tiene muchos accesos concurrentes, se puede aumentar la granularidad y usar el modo de bloqueo a nivel de tupla. Este aumento de la granularidad conlleva a un aumento en la cantidad de objetos bloqueados que se deben mantener, lo que redunda en mayor uso de memoria y una posible baja de performance del motor.

Un nivel de bloqueo por tupla sirve cuando se actualizan pocas tuplas de una tabla, o cuando es necesario actualizar de forma concurrente (desde distintas sesiones) distintas tuplas de la misma página. En este caso, si los bloqueos son por página, es posible que las actualizaciones fallen, o tengan que
esperar que se termine de actualizar una tupla de la misma página.

El tipo de bloqueo por tabla utiliza menos recursos que los bloqueos por página o tupla. Este tiplo de bloqueo se pueden utilizar en procesos batch, cuando es un único proceso que accede a cada tabla de la base de datos. De deben tener recaudos con este bloqueos de tablas en sistemas de tipo OLTP. Ante un bloqueo de una tabla, otros procesos de sólo lectura igual podrán acceder a los datos de la misma.

Para obtener la información acerca del tipo de bloqueo que tienen las tablas de una base podemos ejecutar la sigiuente consulta:

SELECT tabname,locklevel FROM systables WHERE tabid>99

La columna tabname contiene el nombre de la tabla, la columna locklevel contiene ‘P’ si el lock mode es por página, o ‘R’ si es por tupla.

Para crear una tabla con un lock mode determinado lo especificamos al ejecutar el comando CREATE TABLE:

CREATE TABLE customer(customer_num serial, lname char(20)...)
LOCK MODE ROW|PAGE|TABLE;

Para cambiar el lock mode de una tabla utilizamos el comando ALTER TABLE:

ALTER TABLE [tabla]
MODIFY LOCK MODE (PAGE|ROW|TABLE)
Tagged

Diferencias entre transactional unbuffered y transactional buffered en Informix

Vale la pena destacar la diferencia entre estos dos modos de trabajo (logging modes) de las bases de datos de Informix.

Informix siempre persiste los datos escribiendo a alguno de sus buffers de log lógico. Si la base de datos en la cual se están haciendo cambios está trabajando en modo unbuffered, estos cambios se escriben al disco duro inmediatamente después de que un registro de commit o rollback llega al log lógico. Si la base de datos está trabajando en modo buffered, el servidor mantiene estos cambios se mantienen en el log el mayor tiempo posible, hasta que ocurre alguno de los siguiente eventos:

  • Un buffer se llena
  • Se ejecuta un checkpoint
  • Se cierra la conexión contra la base de datos
  • Se hace un commit a una base que está trabajando en modo unbuffered

En el modo buffered, existen problemas si el sistema se bloquea antes de
que el buffer de log lógico sea escrito al disco duro pero después de la transacción que el usuario completó ejecutando un commit. La transacción se considerará incompleta y se ejecutará un rollback cuando el motor sea reiniciado y se recupere. En modo unbuffered esto no sucede ya que luego del commit se escribirán los datos de la transacción en el disco duro y no se perderán.

Por defecto, se trabaja en modo unbuffered. Si bien enlententece un poco el motor, es más robusto que el modo buffered frente a caídas del motor en lo que a pérdida de datos respecta.

El tamaño de los buffers de logs lógicos se pueden averiguar en el archivo onconfig (parámetro LOGBUFF).

Referencias:

Tagged