La problemática de las tablas maestras

9 comentarios

Cuando diseñamos una Base de Datos normalmente creamos cuatro tipos de tablas:

  • Configuración
  • Maestras
  • Movimientos
  • Auxiliares

Las tablas de configuración servirán para guardar datos que ayudarán a personalizar la aplicación relacionada.

Las tablas maestras servirán para guardar datos que luego usarán las tablas de movimientos.

Las tablas de movimientos servirán para guardar lo que ocurre en la operación normal de la empresa u organización, sus actividades diarias. A su vez se clasifican en cabecera y en detalle.

Las tablas auxiliares servirán para guardar datos temporales.

En las tablas de movimientos siempre tenemos una columna donde guardamos la fecha del movimiento, así que no es problema conocer las fechas cuando las necesitamos.

Pero eso muchas veces no ocurre con las tablas maestras, en ellas no se suelen guardar las fechas. Y puede ser muy necesario conocerlas.

Ejemplo:

Tenemos una tabla maestra de CLIENTES donde entre otros datos guardamos el Identificador del Cliente, su Nombre, su Dirección, su Teléfono. Y una tabla cabecera de VENTAS donde guardamos el Identificador de la Venta, el Identificador del Cliente, el Número de la Factura, la Fecha de la venta y otros datos.

Le hacemos una venta al cliente Juan Pérez, e imprimimos la Factura Número “001-002-3456789” que corresponde a esa venta. En ella consta que la Dirección de Juan Pérez es “Colón 12345” y que su teléfono es el “0123-456789”. Todo bien hasta ahí, ningún problema, se va Juan Pérez con su Factura.

Un tiempo después regresa Juan Pérez, le hacemos otra venta, pero nos dice que se mudó y que por lo tanto se cambió su Dirección, su Teléfono y hasta su Localidad. Así que ahora le imprimimos la Factura Número “001-002-9876543” que corresponde a esta última venta, la nueva Dirección es “Spartacus 44444” y el nuevo teléfono es el “0333-555555”. Todo bien hasta ahí, ningún problema, se va Juan Pérez con su Factura.

Pero …. luego surge el problema.

Hay una auditoría, el ente recaudador de impuestos hace un control cruzado entre las Facturas de Juan Pérez y nuestras Facturas y al consultar la Factura “001-002-3456789” le dice que la Dirección es “Spartacus 44444” y el Teléfono es “0333-555555” porque esos son los datos que tenemos guardados de Juan Pérez en nuestra Base de Datos actualmente.

Y está mal.

Está mal porque la Dirección que se imprimió en esa Factura era “Colón 12345”. Y aunque pasen los años y Juan Pérez se mude de casa muchas veces siempre que consultemos los datos de la Factura Número “001-002-3456789” deberíamos ver que la Dirección es “Colón 12345”. No la última Dirección que registramos en nuestra tabla de CLIENTES sino la Dirección original.

¿Cuál es la solución a este problema?

Tenemos tres alternativas, dos malas y una buena.

Una alternativa mala es restaurar un backup de la fecha de la primera venta a Juan Pérez para saber que Dirección teníamos guardada ese día.

Otra alternativa mala es guardar en la tabla cabecera de VENTAS la Dirección, el Teléfono, la Localidad, el Email y otros datos de Juan Pérez. Es cierto que eso nos aseguraría de imprimir siempre los datos correctos pero nuestra tabla no estaría normalizada y por lo tanto gastaríamos mucho más espacio en el disco duro que el necesario.

La alternativa buena es guardar en otra tabla, no en la tabla de CLIENTES sino en otra tabla, los cambios que se realicen a los datos de nuestros clientes. La estructura de esta tabla (la podríamos llamar CAMBIOS_CLIENTES) debería ser idéntica a la tabla CLIENTES pero tendría una columna más, esa columna adicional sería el Identificador de la tabla (el que usamos para su Primary Key).

La tabla CLIENTES (y por lo tanto la tabla CAMBIOS_CLIENTES) debe tener una columna donde se guarde el nombre del usuario que insertó la fila y otra columna donde se guarden la fecha y la hora de esa inserción.

De esta manera siempre podríamos saber cuales eran los datos de Juan Pérez en cualquier día de cualquier mes de cualquier año.

¿Cuál era la Dirección de Juan Pérez el día 12 de agosto de 2013?

  1. Buscamos en la tabla CAMBIOS_CLIENTES la fila más nueva que corresponda a Juan Pérez y que su fecha sea 12 de agosto de 2013 o anterior.
  2. Si la encontramos, esa es la Dirección de Juan Pérez el día 12 de agosto de 2013
  3. Si no la encontramos, buscamos en la tabla CLIENTES cual es la Dirección que originalmente tenía Juan Pérez
  4. Si esa fila fue insertada el día 12 de agosto de 2013 o antes, esa es la respuesta buscada
  5. Si la fila fue insertada posteriormente al 12 de agosto de 2013 entonces Juan Pérez aún no era nuestro cliente ese día y por lo tanto no podemos saber cual era su Dirección.

El problema con las tablas maestras

Lo que vimos en el ejemplo anterior, con las ventas a Juan Pérez y sus cambios de direcciones se aplica a todas las tablas maestras. Cualquier tabla maestra que tengamos adolecerá del mismo problema si no tomamos las debidas precauciones: que estaremos viendo los últimos datos, no los datos que teníamos anteriormente. Y en muchos casos los que deberíamos ver son los datos que teníamos anteriormente.

Una Base de Datos que no puede ser retrotraída a cualquier instante anterior no está bien diseñada.

Es así de simple:

  • Si yo necesito recurrir a un backup para que una consulta me muestre los datos correctos entonces mi Base de Datos está mal diseñada. Nada que discutir.
  • Si las tablas no están normalizadas entonces mi Base de Datos está mal diseñada. Nada que discutir.

Un buen diseño implica más trabajo

Todo tiene sus ventajas y sus desventajas, nada es perfecto. Podemos tener una Base de Datos perfectamente diseñada que nos permita responder a cualquier pregunta en cualquier momento, pero eso demandará más de nuestro tiempo. Y es que por cada tabla maestra deberemos tener una tabla de CAMBIOS. Y por cada tabla maestra deberemos tener un trigger AFTER UPDATE que le inserte una fila a la tabla de CAMBIOS. Y a su vez nuestras consultas (SELECTs) serán más complicadas cuando involucren a las preguntas ¿quién? ¿cuándo? o ¿desde cuándo? y ¿hasta cuándo?

La diferencia entre tener una Base de Datos muy bien diseñada y una pobremente diseñada la verás el día que quieras venderle tu aplicación a gente que entiende de Informática. Mientras tus clientes sean ignorantes en temas informáticos podrás venderles casi cualquier cosa pero el tema es muy distinto cuando hablas con gente entendida. Por ejemplo si una empresa tiene un Departamento de Informática es seguro que tendrás que entrevistarte con los encargados y allí enseguida descubrirán tu pobre diseño.

Por lo tanto, si quieres vender tus aplicaciones a empresas de cualquier tamaño y no pasar vergüenza cuando hables con el personal informático, diseña tu Base de Datos de la mejor manera posible.

Artículos relacionados:

El índice del blog Firebird21

Usando dos servidores para aumentar la velocidad de las operaciones

2 comentarios

Generalmente los usuarios quieren velocidad, quieren que las operaciones que realizan en la Base de Datos (SELECT, INSERT, UPDATE, DELETE) sean muy rápidas.

Una técnica que podemos emplear para aumentar la velocidad (además de la optimización de las consultas, que ya hemos visto en otros artículos de este blog) es tener en la misma computadora dos (o más) servidores instalados.

Como seguramente sabes, Firebird viene en tres arquitecturas: Classic, SuperClassic y SuperServer.

El problema con SuperServer es que mantiene un caché para todas las conexiones. O sea que si una Base de Datos tiene 40 conexiones, hay un solo caché para las 40 conexiones. Y si alguien está ejecutando una transacción o una consulta muy larga eso crea un “cuello de botella” para todos los demás usuarios, haciendo que sus operaciones se vuelvan muy lentas. Pero la gran ventaja de usar un solo caché es que si el usuario 2 quiere hacer la misma consulta que ya hizo el usuario 1 los datos de esa consulta ya muy probablemente se encuentran en el caché y por lo tanto no deben ser leídos del disco duro, proporcionando una gran velocidad (la memoria RAM es miles de veces más rápida que la memoria secundaria).

Como ves, usar SuperServer o usar Classic tiene sus ventajas y sus desventajas.

Entonces, ¿cuál es la mejor solución?

Usar dos servidores.

Un Servidor con la arquitectura SuperServer se usará para el mantenimiento de los datos de la Base de Datos y para las consultas rápidas. Un Servidor con arquitectura Classic se usará para las consultas lentas (que son lentas porque deben procesar muchos datos, no porque están mal diseñadas que ese es otro tema).

Para que esta técnica funcione sin problemas un solo Servidor será el encargado de las operaciones de mantenimiento de los datos (INSERT, UPDATE, DELETE). ¿Por qué? porque si los dos servidores pueden hacerlo podrían ocurrir conflictos y corromperse la Base de Datos. Por lo tanto hay que evitar esa posibilidad.

Entonces:

  • SuperServer se encargará de las operaciones de INSERT, UPDATE, DELETE y SELECTs rápidos
  • Classic se encargará de los SELECTs lentos

Como Classic usa un caché por cada conexión si un usuario está realizando una consulta muy lenta eso no les afectará a los demás usuarios.

¿Entonces, qué conseguimos con esto?

Que todos estén felices.

Los gerentes y los propietarios de las empresas generalmente se conectan a las bases de datos para realizar consultas. Entonces ellos siempre usarán Classic.

Los operadores se encargan de introducir datos y de imprimir informes de comprobación. Para la introducción de datos y para la impresión de informes cortos, usarán SuperServer; para la impresión de los informes que tendrán muchas páginas o que requieren de mucho procesamiento, usarán Classic.

Artículos relacionados:

Modelos de ejecución del Firebird y sus diferencias

Comparando las arquitecturas

Diferencias entre SuperServer, Classic y SuperClassic

El índice del blog Firebird21