Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Firebird e Interbase (https://www.clubdelphi.com/foros/forumdisplay.php?f=19)
-   -   Como distribuir actualización para algunas tablas de una BD Firebird (https://www.clubdelphi.com/foros/showthread.php?t=90315)

Mauro® 16-05-2016 21:20:24

Como distribuir actualización para algunas tablas de una BD Firebird
 
Gente, buenas tardes a todos.
Escribo hoy para ver si alguien puede darme un poco luz sobre un tema que debo resolver.
Estoy realizando una nueva versión de catálogo digital de una empresa y debido a que es necesario mejorar el rendimiento de las búsquedas de información y la administración de los datos he decidido migrar la estructura de datos actualmente en tablas Paradox a Firebird, utilizando Firebird Embedded. Hasta aquí todo bien, pero necesito resolver como distribuir las actualizaciones de Precios y Artículos.
Actualmente la aplicación descarga los archivos Paradox de Artículos y precios y sobrescribe los archivos viejos, pero ahora si migrara a Firebird no podría descargar una nueva base de datos completa, debido a que la estructura tiene otras tablas con configuraciones especificas de cada Usuarios/Cliente además de imágenes de productos con lo cual el peso del archivo seguramente sea de mas 500 mb.
A alguien se le ocurre como podría distribuir esta información de actualización para que luego sea procesada por las instalaciones de los usuarios.

Desde ya muchas gracias a todos.
Saludos Mauro

Casimiro Notevi 16-05-2016 23:03:15

Hola, creo que no se entiende bien el problema que planteas.

rocksoft 16-05-2016 23:13:34

Hola Mauro,

divide y venceras, exporta los datos en un archivo con los datos en insert

Código SQL [-]
INSERT INTO tabla ("ID", "campo1", "ect")
VALUES (1, 'test1', 'test2'

despues divide el archivo en x paquetes y los envias a poquitos.

aunque 500 MB si los comprimes en rar/zip podria bajar a menos de 200 MB

tmsanchez 17-05-2016 03:38:17

Un opción sería tener dos programas:

A) Programa que publica las actualizaciones.-

Programa que corre en el equipo donde está tu catálogo maestro, su función es la siguiente:

1. Genera un archivo en texto plano, cada linea en el archivo es un registro, en cada línea los campos están separados por una coma o por un pipe (|)
2. El programa comprime el archivo en formato .ZIP (con eso te ahorras algo de espacio)
3. Publica el archivo actualizado en un FTP, HTTPS on en el servidor que tengas


B) El programa en el cliente que actualiza

1. El programa se conecta al servidor (FTP, HTTPS, etc.)
2. Descarga el archivo comprimido y lo descomprime
3. Abre al archivo de texto plano
4. Procesa la actualizacion:

Para cada linea del archivo de texto
Parsear para obtener los valores de los campos y almacenarlos por ejemplo en un Record
Arma la sentencia UPDATE (Update tabla set campo1 = :CAMPO1... WHERE llave= :LLAVE)
Asignar los valores del Record (ParamByName('CAMPO1').Value := record.campo1...

Ejecutar un query de actualización y obtiene cuantos registros fueron actualizados
registrosActualizados := query.ExecSQL

si registrosActualizados = 0 entonces ejecutarSentenciaInsert (INSERT INTO tabla (campo1, campo2, campoN) VALUES ( :CAMPO1, :campo2, :campo)

Algo así, espero te sea de utilidad.

mamcx 17-05-2016 05:14:17

Cita:

Empezado por Mauro® (Mensaje 505252)
pero ahora si migrara a Firebird no podría descargar una nueva base de datos completa,

Claro que puedes! Quien te dijo que no puedes tener muchas BD a la vez?

Esto es lo que hago yo:

Genero una BD basada en en los datos de la fuente, comprimo y cuando me llega el archivo reverso el proceso. Claro, en sqlite es muy facil, pero con FB encuentro esto:

http://www.firebirdfaq.org/faq16/
-----

Como sea el proceso es similar no importa el camino que tomes. Yo hago todo con BD porque asi me ahorra el tema de codificar/decodificar los datos y puedo usar SQL como INSERT INTO destino FROM SELECT origen...

----

Una forma solida de hacer la sincronización es agregar un campo tipo INT que se llame "version" que se actualiza cada vez que se cambie una fila basado en la version anterior + 1. Esto es*diferente* del autonumerico: Se hace tanto para INSERT, UPDATE y con DELETE pero logico.

Luego simplemente haces WHERE version > UltimaVersion y obtienes todos los registros cambiados.

Combat-F2D 17-05-2016 07:11:13

Cita:

1. Genera un archivo en texto plano, cada linea en el archivo es un registro, en cada línea los campos están separados por una coma o por un pipe (|)
2. El programa comprime el archivo en formato .ZIP (con eso te ahorras algo de espacio)
Desde que me he decidido a usarlos, son todo beneficios, NO quiero otra cosa

En las Actualizaciones puedes generarlos automáticamnete a modo de log, el como ya lo deberás decidir tu

Por si de algo te vale, yo genero update e insert en una tablet (android) en Sqlite, a modo standalone, sin ninguna conexión.
(paralelamente genero los csv)
Cuando llegado el momento, mediante ftp las descargo al servidor FB y posteriomente los proceso para actualizar el FDB
correspondiente; no es lo mismo pero por ahí te podrian ir los tiros
Lo CSV comprimidos No ocupan nada

Lepe 17-05-2016 14:47:43

No veo problema.

Para actualizar los registros:
El catálogo principal (el maestro), usas un "Extract data" (desde IbExpert es así, desde delphi depende de los componentes IBX, Zeos o el que uses). Casi todos tienen un método que extrae los datos como "insert", "insert or update", o "Merge" (suele llamarse proceso por lote "Batch"), así que extraes todo el contenido de una tabla y lo guardas en un archivo con extensión .SQL, separadas por punto y coma cada instrucción sql. Si quieres borrar siempre el catálogo que tenga el cliente, pues más simple, la primera línea del script sería "delete from catalogo;" y el resto de líneas solo hace inserts.

Si haces uso de imágenes y campos blob, quizás necesites hacer una exportación en formato binario (RAW), o usar tablas externas (ficheros binarios usados para exportar una tabla a disco y después importar)

Para actualizar la definición de la tablas:
Lo mismo, otro archivo .sql pero esta vez las instrucciones son "alter table clientes add certificado_digital varchar(100); " instrucción para añadir un nuevo campo a la tabla clientes.

Actualizador en el cliente:
1º- se baja la definición de las tablas y lo ejecuta con un script:
- IBScript.Script.LoadFromfile(...);
- IbScript.Script.Exectue; esto modifica la estructura de todas las tablas de tu base de datos Firebird, o de las que necesitas.
2º- descarga el fichero de registros. Se hace justo igual que antes, cargando en un Script y ejecutando.

Por supuesto el IBScript tiene eventos que te dice si algo falla, qué instrucción sql falló y si continuar o abortar el proceso de ejecución.

Si quieres guardar un "control de versiones", hay muchas formas, una es guardar cada grupo de actualizaciones en archivos llamados 001.sql, 002.sql y si el cliente tiene la versión 023.sql, solo descarga y ejecuta los scripts del 024.sql hasta el último que encuentre en la carpeta del FTP.

Con todo esto puedes crear procedimientos almacenados, vistas, triggers en la base de dato del cliente. Puedes borrar campos de las tablas y modificar los registros.

NO te aconsejo usar integridad referencial... es un mal consejo desde el punto de vista de diseño de bases de datos, pero ganarás en libertad para modificar la estructura de la base de datos... Imagina este escenario: Tienes varias tablas relacionadas por claves ajenas, (campos foráneos), si borras un registro y se produce un borrado en cascada, actualización y demás, el dolor de cabeza para dejarlo todo cuadrado es demasiado. Créeme, llegará el momento que quieras modificar los datos de una tabla maestra, sin modificar los detalles (típico caso de mover 100 lineas de una factura a otra porque el usuario se equivocó de cliente)

Aconsejo normalizar las tablas, crear el mismo campo en dos tablas que se relacionen, pero no uses el "foreign key" al definir las tablas. Te obliga a escribir 2 sqls al actualizar, borrar una tabla detalle y después la maestra, pero no es nada con el lío de "foreigns keys", te lo garantizo.

Saludos!

mamcx 17-05-2016 18:43:13

Cita:

Empezado por Lepe (Mensaje 505278)
Aconsejo normalizar las tablas, crear el mismo campo en dos tablas que se relacionen, pero no uses el "foreign key" al definir las tablas. Te obliga a escribir 2 sqls al actualizar, borrar una tabla detalle y después la maestra, pero no es nada con el lío de "foreigns keys", te lo garantizo.

Saludos!

No entiendo esto. Anular los chequeos de integridad solo hace que sea mas dificil (o imposible) darse cuenta si algo salio mal. De eso vivi muchos problemas cuando usaba tablas de dbase y aun no tenian esos chequeos.

Si los tiros van por desnormalizar los datos que se envian para sincronizar y re-aplicarlos en un esquema local (que si tiene todos los check activos) eso esta bien.

Ahora, el lio que planteas (maestros, detalles, relaciones) es el problema de la sincronizacion, pero es un problema que se resuelve usando EXACTAMENTE lo mismo que usan las BD para mantener su salud antes las fallas, el LOG.

Este articulo es altamente esclarecedor:

https://engineering.linkedin.com/dis...datas-unifying

Ahora todo esto lo llaman EVENT SOURCING:

http://martinfowler.com/eaaDev/EventSourcing.html
----

Sincronizar una tabla es facil, pero como se hace cuando son relaciones y demas? El truco es entender que estamos hablando de como los datos se mueven en el TIEMPO. Asi, que si se hace un intento ingenuo de usar TIMESTAMPS o campos VERSION va a ser muy dificil porque esos campos carecen de la informacion para reconstruir como se movio no solo el REGISTRO, sino el conjunto de ellos entre todas las tablas.

Asi que lo que hay que hacer para hacer un sync robusto y no perder ninguna de las ventajas del modelo relacional, es hacer un LOG!

Ej:

1- INSERTADO: Encabezado = 1 WITH Data(.......)
2- CAMBIADO: Encabezado = 1 WITH ....
3- INSERTADO: Detalle = 1 WITH ....
4- INSERTADO: Detalle = 2 WITH ....
5- BORRADO: Detalle = 1 WITH ....

Noten como el log captura de forma NATURAL el orden de los pasos. Asi que solo hay que leer el log para recuperar el estado de los registros.

NO IMPORTA SI LEES EL LOG PARCIAL, mientras allas empezado desde el principio y sigas de forma secuencial, puedes parar en CUALQUIER momento, y continuar despues y al final tendras una lectura consistente.

Este log es LOGICO. De hecho, es mejor hacerlo usando lenguaje de negocios:

1- CREADA.FACTURA con DATOS =
1- CAMBIADA.FACTURA con DATOS =
1- CREADA.DETALLE...

Noten, es IMPORTANTE: Siempre se hace log sobre lo que ocurrio en EL PASADO. Por lo tanto, es despues de haber hecho todas las validaciones, y de haber asignado los datos en la tabla(s) de destino. De esta forma, se garantiza que cada linea representa un hecho consistente y confiable, y que si se borran TODOS los registros de la BD, se puede usar solamente el LOG y al final tendras la misma info de antes.

EXACTAMENTE como hacen los motores para manejar sus transacciones, sus backups, replicarse y demas.

EXACTAMENTE como el modelo contable: SI has registrado correctamente todos los asientos, se debe poder re-construir TODOS LOS DOCUMENTOS en base a esto. (Eso es lo que en la antiguedad hacia la opcion de "Reconstruir los datos" que usaban los programas de facturas hechos en DOS. Como los engine eran poco confiables y sin FOREIGN KEYS, transacciones, CHECK y demas mejoras que trajeron las BD modernas, los datos se desincronizaban y/o perdian, asi que tocaba recurrir al diario de transacciones para reconstruir los datos)

Casimiro Notevi 17-05-2016 18:56:49

Cita:

Empezado por Lepe (Mensaje 505278)
NO te aconsejo usar integridad referencial... es un mal consejo desde el punto de vista de diseño de bases de datos, pero ganarás en libertad para modificar la estructura de la base de datos...

Corramos un tupido velo...


La franja horaria es GMT +2. Ahora son las 21:27:40.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi