¿Es una mala práctica agregar datos de diferentes tablas en una?

12

Antecedentes

Escribo muchos informes grandes y generalmente mantengo una base de datos de registros de salud grandes (escribo SP, funciones, trabajos, etc.). El esquema original, y el software que lo usa, es de un proveedor diferente, por lo que no puedo cambiar mucho estructuralmente. Hay muchos registros que requieren seguimiento, como laboratorios, procedimientos, vacunas, etc., y están dispersos en docenas de tablas, muchas de las cuales están hinchadas y mal indexadas (he podido solucionar esto de alguna manera).

El problema

El problema es que debido a que tenemos poco control sobre el DB, y dado que puede cambiar desde cualquier actualización o parche, hace que escribir y mantener estos informes sea difícil y tedioso, especialmente cuando hay una gran cantidad de superposición. Todo lo que se necesita es un parche y estoy atascado reescribiendo grandes porciones de una docena de informes. Además, las consultas se ofuscan rápidamente y se ralentizan a medida que las uniones, las selecciones anidadas y las aplicaciones se acumulan.

Mi solución"

Mi plan era escribir todos estos registros en una tabla "general" y escribir desencadenantes en las tablas originales para mantener los registros en esta tabla agregada. Por supuesto, tendría que asegurarme de que mis disparadores estuvieran intactos después de las actualizaciones, pero esto sería mucho más fácil desde el punto de vista de la mantenibilidad, y solo haciendo referencia a los datos.

La tabla sería delgada y larga, almacenando solo los datos requeridos, algo como esto:

CREATE TABLE dbo.HCM_Event_Log (
    id INT IDENTITY,
    type_id INT NULL,
    orig_id VARCHAR(36) NULL,
    patient_id UNIQUEIDENTIFIER NOT NULL,
    visit_id UNIQUEIDENTIFIER NULL,
    lookup_id VARCHAR(50) NULL,
    status VARCHAR(15) NULL,
    ordered_datetime DATETIME NULL,
    completed_datetime DATETIME NULL,
    CONSTRAINT PK_HCM_Event_Log PRIMARY KEY CLUSTERED (id)
)

Luego tendría varias tablas relacionales para cosas como type_id y agrupaciones de elementos.

Estoy empezando a adivinar esta idea, ya que varias de estas tablas se escriben bastante, los SP e informes que escribiría también harían referencia a los datos. Por lo tanto, me preocupa que esta tabla se convierta en una pesadilla de bloqueo de registros y rendimiento con tanta E / S.

Mi pregunta

¿Es una mala o una buena idea? Me doy cuenta de que cada situación es diferente en SQL Server (2008 r2 Standard Edition BTW) y la regla de "a veces", pero realmente solo estoy buscando consejos generales.

Comencé a considerar el uso de un intermediario de servicios, pero solo realizaría actualizaciones / inserciones simples ( consulte la alternativa a la respuesta aceptada ). Los datos en muchos casos deben ser en tiempo real, por lo que el uso de una base de datos de respaldo no funcionaría realmente. El rendimiento ya es un problema para nosotros, pero la mayor parte de eso está relacionado con el hardware que se resolverá pronto.

jreed121
fuente
1
¿Se puede hacer cumplir los cortes planeados? Si ninguna de esas actualizaciones podría eliminar un desencadenante y no actualizará sus agregados, posiblemente conduzca a datos incorrectos.
Erik
¿Está considerando poner toda la información sobre los laboratorios, los procedimientos, las vacunas y los pacientes en una sola tabla? Mala idea. Es posible que pueda usar un esquema en estrella, si eso se adapta al tipo de consultas que está ejecutando.
Michael Green
1
¿Has pensado en crear algunas vistas indexadas? Esto pondría una capa lógica entre su código y el del proveedor para que pueda actualizar la vista si el proveedor cambia las cosas debajo. Además, las vistas indizadas se completarán previamente para usted y proporcionarán un buen rendimiento de lectura. Una de las consideraciones más importantes al hacer esto es cuánta carga pone en las operaciones de escritura de las tablas de la base de datos del proveedor. Sin embargo, esta sería una solución más limpia y más fácil de mantener que usar disparadores, etc.
Micah Nikkel
Perdón por la respuesta tardía chicos, gracias por los comentarios. @Erik - Sí, tenemos actualizaciones planificadas, y verifico para asegurarme de que todos mis cambios anteriores todavía estén en su lugar a través de una serie de scripts de lista de verificación que ejecuto, por lo que no habrá sorpresas allí y seguiré CREANDO scripts para Todos los disparadores.
jreed121
@MichaelGreen: analizaré un esquema de estrella, pero tengo curiosidad por qué piensas que tener todos esos datos en una tabla es una mala idea. El entorno de la aplicación está completamente aislado en una VPN, de todos modos no es accesible fuera de la red. Si algo sale mal en la mesa, entonces no es el fin del mundo porque podría simplemente escribirle todo. La tabla no se usará para datos de misión crítica, o al menos no será el único, ni el principal, lugar donde se almacenan los datos.
jreed121

Respuestas:

8

Si te entendí correctamente,

  • tienes un gran sistema de terceros,
  • no tienes mucho control sobre eso,
  • realiza informes complejos que leen datos directamente de esta base de datos de terceros,
  • sus consultas dependen de la estructura interna de la base de datos de terceros.

Lo abordaría así:

  • Configurar mi propia base de datos separada, de la que tengo control total.
  • Configure un proceso de sincronización que lea datos de tablas y columnas relevantes de la base de datos de terceros e inserte / actualice en la mía.
  • Desarrollar mis informes complejos basados ​​en la estructura estable de mi base de datos.

En este caso, puede ajustar la estructura y los índices de su base de datos para mejorar el rendimiento de sus informes, sin afectar el sistema de terceros. A menos que la estructura de datos original cambie drásticamente, la lógica de sus consultas para sus informes no cambiaría si cambia la base de datos de terceros. Tendría que ajustar solo el proceso de sincronización.

El proceso de sincronización es efectivamente el proceso de conversión : convierte datos de bases de datos de terceros en la estructura que necesita. Parte de este proceso de conversión podría estar solucionando cualquier problema de normalización que pueda tener la base de datos de terceros original. Solo esta parte del sistema tiene que conocer y depender de la estructura interna del sistema de terceros. Sus informes principales y consultas principales dependerán solo de su base de datos.

Por lo tanto, el punto principal es: separar y limitar la parte de su sistema que depende de los componentes internos de un sistema de terceros.

actualizar

En cuanto a los requisitos en tiempo real. Por cierto, siempre pensé que la definición de "tiempo real" es "tiempo de respuesta garantizado", no "un tiempo de respuesta pequeño". Depende de su aplicación, por supuesto. En mi práctica, es suficiente si sincronizo dos bases de datos dentro de un minuto del cambio detectado. Si un usuario ve un informe en la pantalla y algunos cambios en los datos subyacentes, el informe debe volver a ejecutarse de alguna manera para reflejar este cambio. Puede sondear los cambios o escuchar algún evento / mensaje, pero la consulta del informe debe ejecutarse nuevamente para mostrar los últimos cambios.

Ya tiene la intención de escribir disparadores para capturar los cambios en las tablas originales y escribir estos cambios en una tabla genérica. Por lo tanto, capture los cambios como pretendía, pero escríbalos en tablas correctamente normalizadas, no en una sola.

Entonces, este es un caso extremo: la conversión de la estructura de datos de terceros en su estructura de datos interna se realiza en los disparadores que se activan en las INSERT/UPDATE/DELETEtablas de terceros. Puede ser complicado El código de los disparadores dependería de la estructura interna de ambos sistemas. Si la conversión no es trivial, puede retrasar el original INSERT/UPDATE/DELETEhasta el punto de su falla. Si hay un error en su activador, puede afectar la transacción original hasta el punto de su falla. Si el sistema de un tercero cambia, puede romper su disparador, lo que provocaría un error en las transacciones del sistema de terceros.

Caso menos extremo. Para hacer que el código de sus desencadenantes sea más simple y menos propenso a errores, escriba todos los cambios capturados en algunas tablas de etapas / auditoría / diferencias, establezca algún indicador / envíe un mensaje de que hay cambios pendientes e inicie el proceso de conversión principal que iría a través de estas tablas intermedias y realizar la conversión. Lo principal aquí es que el proceso de conversión potencialmente pesado debe ocurrir fuera del alcance de la transacción original.

En un segundo vistazo, se parece bastante a su sugerencia original en la pregunta. Pero, la diferencia es: las tablas de capturar todo contienen datos solo temporalmente; la cantidad de datos es pequeña, solo lo que ha cambiado; no tiene que ser una sola mesa; finalmente, los datos se almacenarán en tablas permanentes separadas debidamente normalizadas, de las cuales usted tiene control total, que son independientes del sistema de terceros y que puede ajustar para sus consultas.

Vladimir Baranov
fuente
Si va por la ruta de transferencia por lotes, hemos tenido éxito con Change Tracking (y Change Data Capture, según sus necesidades) con recuentos de transacciones bastante altos (100K por día). Es más simple que implementar sus propias tablas de preparación / auditoría / diff y se puede implementar sin cambios en el código de la aplicación o desencadenantes.
Michael Green
Ya se trate de disparadores o CDC, la única forma en que realmente se acercará al tiempo real es transmitiendo o haciendo cola. Basado en la cola es un buen compromiso para la latencia y la rentabilidad. Su tiempo se gastará en métodos para procesar la cola más rápido. dejando la mayor parte del trabajo asíncrono desde la aplicación y poniendo menos carga en las transacciones del usuario. En el pasado, he hecho esto contra el EMR de Allscripts Sunrise con un servicio que procesó la cola con algunas llamadas paralelas de C # foreach. la latencia típica para que los nuevos datos se procesen y estén disponibles en el almacén fue inferior a 30 segundos
Brad D
Es posible que haya declarado "en tiempo real", no estoy demasiado preocupado con milisegundos o incluso 5 segundos, pero tengo muchas consultas en las que nuestro personal confía para impulsar el flujo de trabajo. Si un cliente le hizo algo (procedimiento, inmunización, etc.), tendremos que demostrarlo en un corto período de tiempo. Las conversiones son triviales, y / o ni siquiera conversiones. No estoy demasiado preocupado con el cambio en las tablas de proveedores, ya que no cambian tan a menudo, y tengo que hacerlo ahora de todos modos, pero pensé que es más fácil actualizar / recrear un disparador que una docena de informes / consultas / SPs. Ejecuto controles después de cada actualización.
jreed121
@ jreed121, también creo que es más fácil actualizar los desencadenantes que los informes. Es probable que tenga un activador en cada tabla de origen para capturar los cambios, por lo que es probable que sea más de un activador. Aún así, no intente escribir todos estos cambios capturados en una gran tabla desnormalizada. Escríbalos en un conjunto de tablas correctamente normalizado. Sus informes deben basarse en estas tablas normalizadas que usted controla y no deben depender de las tablas originales que pueden cambiar.
Vladimir Baranov
3

Por supuesto, colóquelo en un conjunto estandarizado de tablas para que pueda modificar la etapa de importación en lugar de tener que cambiar informes complejos y consultas. Pero los datos aún deben normalizarse, lo que requerirá tablas múltiples (pero con buenos índices).

Como otros han mencionado, no use disparadores, sincronice en lotes.

No se preocupe por muchas uniones, cuando los datos se normalizan e indexan correctamente, estos no agregan ningún costo significativo o carga administrativa.

El momento de desnormalizar en algo como un almacén de datos es cuando necesita poder realizar muchos tipos diferentes de consultas sobre los datos que no puede predecir. Tiene sus propias desventajas y gastos generales y debe usarse donde sea apropiado, no como un recurso de referencia.

JamesRyan
fuente
3

Trabajé con una situación muy similar como esta en el pasado en una empresa de fabricación 24x7 y finalmente decidí usar la replicación transaccional. Es posible configurar DDL para que se replique de manera que pueda enviar cualquier cambio que el parche cambie al suscriptor. Obviamente, hay pros y contras en todo y debe sopesarlos para determinar qué puede respaldar contra lo que funciona mejor para la empresa.

En el lado positivo:

  1. El "tiempo real" se limita solo al rendimiento de la red y del compromiso de transacción en el suscriptor. En mi experiencia con un sistema TPS moderadamente alto, fuimos replicados en menos de 10 segundos de datos "en tiempo real".
  2. Separación de cargas de trabajo. Actualmente está ejecutando una carga de trabajo mixta en un servidor. Si puede separar estas dos preocupaciones, entonces puede obtener los beneficios de rendimiento en ambos sistemas de haber eliminado una carga de trabajo de la ecuación
  3. Controlar. Podrá realizar modificaciones de indexación / estadísticas / mantenimiento para adaptarse a su carga de trabajo de informes.

Sin embargo, hay inconvenientes:

  1. Costo. Otra licencia y más hardware (virtual o de otro tipo).
  2. Replicación. Funciona muy bien una vez que se ha configurado correctamente, pero puede ser una molestia llegar a ese punto.
  3. Mantenimiento. Si realiza cambios perjudiciales en las estructuras (por ejemplo, descartar un índice), volverán cuando se aplique la instantánea (después de que la publicación haya cambiado o cuando los artículos hayan cambiado).
swasheck
fuente
2

Mi plan era escribir todos estos registros en una tabla "general" y escribir desencadenantes en las tablas originales para mantener los registros en esta tabla agregada.

Los disparadores tienen tantos problemas que debes evitarlos:

  • Un error en un disparador puede hacer que la transacción original se cancele
  • Los disparadores que manejan correctamente las operaciones de varias filas son difíciles de escribir
  • Los desencadenantes pueden confundir las aplicaciones del cliente al modificar el conjunto de filas devuelto (por ejemplo, un desencadenador anula el número de filas afectadas)
  • Cuando un desencadenante desencadena otro, los resultados son difíciles de predecir

Una mejor opción es un trabajo que copia periódicamente los datos en una nueva tabla. Sus informes pueden ejecutarse de la copia. Un trabajo que copia filas es fácil de escribir y mantener, y no hay riesgo de que afecte el funcionamiento de la aplicación de terceros.

Andomar
fuente
1. Los desencadenantes serían simples, por lo que los errores arrojados serían mínimos si es que existen. 2. El disparador en sí mismo no manejaría varias filas (es decir, una fila actualizada en la tabla con el disparador no haría que se actualizaran varias filas en otro lugar), pero se podrían insertar / actualizar / eliminar varias filas a la vez en la fuente mesa - ¿es esto lo que quieres decir? 3. ¿ No se puede manejar esto NOCOUNT? 4. No habría desencadenantes en la tabla de destino, y podría asegurar lo mismo para los demás.
jreed121
Como usted dice, es teóricamente posible hacer que los disparadores funcionen. Es solo que en la práctica nunca lo hacen.
Andomar