È una pratica scorretta aggregare i dati di diverse tabelle in una sola?


12

sfondo

Scrivo molti report di grandi dimensioni e in genere conservo un database di record sanitari di grandi dimensioni (scrivere SP, funzioni, lavori, ecc.). Lo schema originale e il software che lo utilizza provengono da un fornitore diverso, quindi non posso cambiare molto strutturalmente. Ci sono molti documenti che richiedono il monitoraggio come laboratori, procedure, vaccini, ecc. E sono sparsi su dozzine di tavoli, molti dei quali sono gonfiati e scarsamente indicizzati (sono stato in grado di risolvere un po ').

Il problema

Il problema è che, poiché abbiamo scarso controllo sul DB e poiché può cambiare da qualsiasi dato aggiornamento o patch, rende difficile e noiosa la scrittura e la gestione di questi report, soprattutto in presenza di grandi sovrapposizioni. Basta una sola patch e sono bloccato a riscrivere gran parte di una dozzina di rapporti. Inoltre, le query diventano rapidamente offuscate e lente man mano che i join, il nidificato vengono selezionati e applicati si accumulano.

La mia "soluzione"

Il mio piano era di scrivere tutti questi record in una tabella "catch-all" e scrivere trigger sulle tabelle originali per mantenere i record in questa tabella aggregata. Ovviamente avrei bisogno di assicurarmi che i miei trigger fossero intatti dopo gli aggiornamenti, ma questo sarebbe molto più facile dal punto di vista della manutenibilità e facendo semplicemente riferimento ai dati.

La tabella sarebbe sottile e lunga, memorizzando solo i dati richiesti, qualcosa del genere:

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)
)

Quindi avrei varie tabelle relazionali per cose come type_id e raggruppamenti di elementi.

Sto iniziando a indovinare questa idea dato che molte di queste tabelle sono state scritte un po ', gli SP e i rapporti che scrivo farebbero riferimento anche ai dati. Quindi sono preoccupato che questa tabella diventi un incubo per il blocco dei record e delle prestazioni con così tanti I / O.

La mia domanda

È una cattiva o una buona idea? Mi rendo conto che ogni situazione è diversa in SQL Server (2008 r2 Standard Edition BTW) e nella regola "a volte", ma sto davvero cercando consigli generali.

Ho iniziato a considerare l'utilizzo di un broker di servizi, ma eseguivo solo semplici aggiornamenti / inserimenti ( vedi l'alternativa alla risposta accettata ). In molti casi i dati devono essere in tempo reale, quindi l'utilizzo di un DB di backup non funzionerebbe davvero. Le prestazioni sono già un po 'un problema per noi, ma la maggior parte è legata all'hardware che verrà risolta presto.


1
Puoi imporre interruzioni pianificate? Altrimenti, nessuno di questi aggiornamenti potrebbe cancellare un trigger e non aggiornerai i tuoi aggregati, portando probabilmente a dati errati.
Erik

Stai pensando di mettere tutte le informazioni sui laboratori, sulle procedure, sui vaccini e sui pazienti in un'unica tabella? Cattiva idea. Potresti essere in grado di utilizzare uno schema a stella, se adatto al tipo di query che stai eseguendo.
Michael Green,

1
Hai cercato di creare alcune viste indicizzate? Ciò metterebbe un livello logico tra il codice e il fornitore in modo da poter semplicemente aggiornare la vista se il fornitore cambia le cose sottostanti. Inoltre, le viste indicizzate verrebbero prepopolate per te e fornire buone prestazioni di lettura. Una delle considerazioni più importanti nel fare questo è quanto carico carica sulle operazioni di scrittura delle tabelle del database del fornitore. Tuttavia, questa sarebbe probabilmente una soluzione più pulita e più facile da mantenere rispetto all'utilizzo di trigger, ecc.
Micah Nikkel

Ci scusiamo per la risposta in ritardo ragazzi, grazie per il feedback. @Erik - Sì, abbiamo pianificato gli aggiornamenti e controllo per assicurarmi che tutte le mie modifiche precedenti siano ancora in atto tramite una serie di script dell'elenco di controllo che eseguo, quindi non ci saranno sorprese lì e terrò gli script CREATE per tutti i trigger.
jreed121,

@MichaelGreen - Esaminerò uno schema a stella, ma sono curioso di sapere perché pensi che avere tutti quei dati in una tabella sia una cattiva idea? L'ambiente applicativo è completamente isolato su una VPN, non è comunque accessibile al di fuori della rete. Se qualcosa va storto con il tavolo, allora non è la fine del mondo perché potrei semplicemente riscrivere tutto. La tabella non verrà utilizzata per i dati mission-critical, o almeno non sarà l'unico, né primario, luogo in cui i dati vengono archiviati.
jreed121,

Risposte:


8

Se ti capissi correttamente,

  • hai un grande sistema di terze parti,
  • non hai molto controllo su di esso,
  • fai report complessi che leggono i dati direttamente da questo database di terze parti,
  • le tue query dipendono dalla struttura interna del database di terze parti.

Mi avvicinerei così:

  • Imposta il mio database separato, di cui ho il pieno controllo.
  • Imposta un processo di sincronizzazione che legge i dati da tabelle e colonne pertinenti dal database di terze parti e inserisce / aggiorna nei miei.
  • Sviluppa i miei report complessi basati sulla struttura stabile del mio database.

In questo caso è possibile ottimizzare la struttura e gli indici del database per migliorare le prestazioni dei report, senza influire sul sistema di terze parti. A meno che la struttura dei dati originale non cambi radicalmente, la logica delle query per i report non cambierebbe se cambiassero database di terze parti. Dovresti modificare solo il processo di sincronizzazione.

Il processo di sincronizzazione è effettivamente il processo di conversione : converti i dati da database di terze parti nella struttura di cui hai bisogno. Parte di questo processo di conversione potrebbe essere risolvere eventuali problemi di normalizzazione che potrebbe avere il database di terze parti originale. Solo questa parte del sistema deve conoscere e dipendere dalla struttura interna del sistema di terze parti. I report principali e le query principali dipenderanno solo dal database.

Quindi, il punto principale è: separare e limitare la parte del sistema che dipende dagli interni del sistema di terze parti.

aggiornare

Per quanto riguarda i requisiti in tempo reale. A proposito, ho sempre pensato che la definizione di "tempo reale" sia "tempo di risposta garantito", non "tempo di risposta ridotto". Dipende dalla tua applicazione, ovviamente. Nella mia pratica è sufficiente sincronizzare due database entro un minuto dalla modifica rilevata. Se un utente visualizza un report sullo schermo e alcune modifiche ai dati sottostanti, il report deve essere in qualche modo rieseguito per riflettere questa modifica. È possibile eseguire il polling per le modifiche o ascoltare alcuni eventi / messaggi, tuttavia la query del report deve essere nuovamente eseguita per mostrare le ultime modifiche.

Hai già intenzione di scrivere trigger per acquisire le modifiche nelle tabelle originali e scrivere queste modifiche in una tabella generica. Quindi, acquisisci le modifiche come previsto, ma scrivile su tabelle correttamente normalizzate, non una sola.

Quindi, questo è un caso estremo: la conversione della struttura di dati di terze parti nella struttura di dati interna viene eseguita nei trigger che si attivano su INSERT/UPDATE/DELETEtabelle di terze parti. Può essere complicato. Il codice dei trigger dipende dalla struttura interna di entrambi i sistemi. Se la conversione non è banale, può ritardare l'originale INSERT/UPDATE/DELETEal punto del loro fallimento. Se è presente un bug nel trigger, potrebbe influire sulla transazione originale fino al punto del loro errore. Se il sistema di terze parti cambia, potrebbe interrompere il trigger, causando il fallimento delle transazioni del sistema di terze parti.

Caso meno estremo. Per rendere il codice dei trigger più semplice e meno soggetto a errori, scrivere tutte le modifiche acquisite su alcune tabelle di staging / audit / diff, impostare alcuni flag / inviare un messaggio in attesa di modifiche e avviare il processo di conversione principale che andrebbe attraverso queste tabelle intermedie ed eseguire la conversione. La cosa principale qui è che il processo di conversione potenzialmente pesante dovrebbe avvenire al di fuori dell'ambito della transazione originale.

A una seconda occhiata assomiglia più o meno al tuo suggerimento originale nella domanda. Ma la differenza è: le tabelle di acquisizione di tutti contengono dati solo temporaneamente; la quantità di dati è piccola, proprio ciò che è cambiato; non deve essere un unico tavolo; alla fine i dati verranno archiviati in tabelle permanenti separate, opportunamente normalizzate, di cui hai il pieno controllo, che sono indipendenti dal sistema di terze parti e che puoi sintonizzare per le tue query.


Se stai seguendo il percorso di trasferimento batch, abbiamo avuto successo con il rilevamento delle modifiche (e Change Data Capture, a seconda delle tue esigenze) con conteggi delle transazioni piuttosto elevati (100.000 al giorno). È più semplice dell'implementazione delle proprie tabelle di gestione temporanea / controllo / diff e può essere distribuito senza modifiche o trigger del codice dell'applicazione.
Michael Green,

Che si tratti di trigger o CDC, l'unico modo per avvicinarti davvero in tempo reale è lo streaming o l'accodamento. Basato sulla coda è un buon compromesso per latenza ed economicità. Il tuo tempo sarà dedicato ai metodi per elaborare la coda più velocemente. lasciando la maggior parte del lavoro asincrona dall'applicazione e caricando meno le transazioni dell'utente. In passato ho fatto proprio questo contro Allscripts Sunrise EMR con un servizio che ha elaborato la coda con alcune chiamate C # parallele foreach. la latenza tipica per l'elaborazione e la disponibilità di nuovi dati nel magazzino era inferiore a 30 secondi
Brad D

Potrei aver dichiarato oltre "in tempo reale", non sono troppo preoccupato per i millisecondi o anche per 5 secondi, ma ho molte domande su cui il nostro staff si affida per guidare il flusso di lavoro. Se un cliente ha fatto loro qualcosa (procedura, immunizzazione, ecc.), Dovremo mostrarlo in breve tempo. Le conversioni sono banali e / o nemmeno conversioni. Non mi preoccupo eccessivamente delle modifiche alle tabelle dei fornitori, in quanto non cambiano spesso, e ora devo farlo comunque, ma il mio pensiero era che è più semplice aggiornare / ricreare un trigger rispetto a dozzine di report / query / SP. Eseguo i controlli dopo ogni aggiornamento.
jreed121,

@ jreed121, penso anche che sia più semplice aggiornare i trigger rispetto ai report. Probabilmente avrai un trigger su ogni tabella di origine per acquisire le modifiche, quindi è probabile che sia più di un trigger. Tuttavia, non provare a scrivere tutte queste modifiche acquisite in un'unica enorme tabella denormalizzata. Scrivili su un set di tabelle correttamente normalizzato. I rapporti dovrebbero essere basati su queste tabelle normalizzate che controlli e non dovrebbero dipendere da tabelle originali che potrebbero cambiare.
Vladimir Baranov,

3

Inseriscilo in una serie standardizzata di tabelle in modo da poter modificare la fase di importazione anziché dover modificare report e query complessi. Ma i dati dovrebbero comunque essere normalizzati, il che richiederà tabelle multiple (ma con buoni indici).

Come altri hanno già detto, non usare i trigger, sincronizza in batch.

Non preoccuparti di molti join, quando i dati vengono normalizzati e indicizzati correttamente, questi non comportano costi significativi o oneri di gestione.

Il tempo di denormalizzare in qualcosa di simile a un data warehouse è quando è necessario essere in grado di eseguire molti tipi diversi di query sui dati che non è possibile prevedere. Ha i suoi svantaggi e costi generali e dovrebbe essere usato dove appropriato, non come cosa da fare.


3

Ho lavorato con una situazione molto simile come questa in passato in un'azienda manifatturiera 24x7 e alla fine ho deciso di utilizzare la replica transazionale. È possibile configurare DDL in modo che venga replicato in modo tale da poter inviare qualsiasi abbonamento al sottoscrittore. Ovviamente ci sono pro e contro in tutto e devi valutarli per determinare cosa puoi supportare rispetto a ciò che funziona meglio per l'azienda.

Sul lato positivo:

  1. "Tempo reale" è limitato solo alle prestazioni di commit della rete e delle transazioni sull'abbonato. Nella mia esperienza con un sistema TPS moderatamente alto, siamo stati replicati in meno di 10 secondi di dati "in tempo reale".
  2. Separazione dei carichi di lavoro. Attualmente stai eseguendo un carico di lavoro misto su un server. Se riesci a separare queste due preoccupazioni, potresti essere in grado di ottenere i vantaggi in termini di prestazioni su entrambi i sistemi di aver rimosso un carico di lavoro dall'equazione
  3. Controllo. Sarai in grado di apportare modifiche all'indicizzazione / statistiche / manutenzione in base al carico di lavoro dei rapporti.

Ci sono contro, tuttavia:

  1. Costo. Un'altra licenza e altro hardware (virtuale o di altro tipo).
  2. Replica. Funziona alla grande una volta che è stato impostato correttamente, ma può essere una seccatura arrivare a quel punto.
  3. Manutenzione. Se si apportano modifiche deleterie alle strutture (ad es. Rilasciare un indice), verranno restituite quando viene applicata l'istantanea (dopo che la pubblicazione è stata modificata o quando gli articoli sono cambiati).

2

Il mio piano era di scrivere tutti questi record in una tabella "catch-all" e scrivere trigger sulle tabelle originali per mantenere i record in questa tabella aggregata.

I trigger hanno così tanti problemi che dovresti evitarli:

  • Un errore in un trigger può causare l'interruzione della transazione originale
  • I trigger che gestiscono correttamente le operazioni multi-riga sono difficili da scrivere
  • I trigger possono confondere le applicazioni client modificando il set di righe restituito (ad esempio, un trigger sostituisce il numero di righe interessate)
  • Quando un trigger ne attiva un altro, i risultati sono difficili da prevedere

Un'opzione migliore è un lavoro che copia periodicamente i dati in una nuova tabella. I rapporti possono essere eseguiti della copia. Un lavoro che copia le righe è facile da scrivere e gestire e non vi è alcun rischio che influisca sul funzionamento dell'applicazione di terze parti.


1. I trigger sarebbero semplici, quindi gli errori generati sarebbero minimi se esistessero affatto. 2. Il trigger stesso non gestirà più righe (IE una riga aggiornata nella tabella con il trigger non causerebbe l'aggiornamento di più righe altrove), ma più righe potrebbero essere inserite / aggiornate / eliminate contemporaneamente nell'origine tabella - è questo che vuoi dire? 3. Non è possibile gestirlo NOCOUNT? 4. Non ci sarebbero trigger sulla tabella di destinazione e potrei garantire lo stesso per gli altri.
jreed121,

Come dici tu, è teoricamente possibile far funzionare i trigger. È solo che in pratica non lo fanno mai.
Andomar,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.