È una cattiva pratica avere una colonna "stato record" in una tabella di database?


12

Devo prima chiarire che la colonna dello stato non intende riflettere lo stato di un elemento del mondo reale rappresentato dal record (riga) nella tabella. Piuttosto, è destinato a mostrare lo stato del record stesso.

Può essere semplice come Attivo / Inattivo o complicato come Approvato / Eliminato / Bloccato / In attesa / Rifiutato, ecc. Lo stato può essere memorizzato su una colonna intera booleana / corta o su una colonna a carattere singolo, con mappature come true/ 1= Attivo o A= Approvato

L'idea di base è di avere un supporto di recupero simile a cestino / cestino nell'applicazione (e simularlo nel database). Se esiste una GUI front-end o un'altra interfaccia che presumibilmente può consentire a un utente di "eliminare" i record, in realtà non elimina il record nella tabella, ma cambia semplicemente lo stato del record in Inattivo o Eliminato. Quando l'interfaccia recupera i record, ottiene sempre i record che corrispondono solo alla condizione che lo stato sia Attivo o Approvato.

Se l'utente commette un errore e il record "eliminato" (nella prospettiva dell'utente) deve essere recuperato, un DBA può facilmente ripristinare il record in Attivo o Approvato, il che sarebbe meglio che cercare backup e sperare di trovare il record originale Là. Oppure l'interfaccia stessa può consentire all'utente di visualizzare i record eliminati in una vista separata e ripristinarli in base alle esigenze, o addirittura eliminarli definitivamente (eliminando il record effettivo).

Le mie domande:

  • È una buona pratica o una cattiva pratica?
  • Influisce sulla normalizzazione dei dati?
  • Quali sono le potenziali insidie?
  • Esiste un metodo alternativo per raggiungere lo stesso obiettivo? (Vedi nota)
  • Come si può fare in modo che il database imponga vincoli univoci sui dati solo per un determinato stato (ma consentire un numero qualsiasi di duplicati per altri stati)?
  • Perché i database non forniscono una funzionalità simile al "cestino" o il rilevamento / recupero della tabella in modo nativo, in modo che possiamo consentire alle interfacce di eliminare i record effettivi senza preoccupazioni?

Nota: ho letto del mantenimento di una tabella di cronologia separata, ma ciò sembra peggiore in termini di archiviazione e di dover generare trigger e mantenere i trigger aggiornati con lo schema della tabella tracciata.


Il problema con i vincoli univoci (che hai già nominato) è esattamente il motivo per cui le tabelle di cronologia sono spesso preferibili: puoi mantenere i vincoli di chiave univoci nelle tabelle originali e non aggiungerli alla tabella di cronologia. Inoltre, tabelle di cronologia separate consentono più facilmente utilizzare per loro opzioni di archiviazione specifiche (dipendenti dal DB), quindi spesso sono migliori in termini di archiviazione, non peggio. Quando disponi di molte di queste tabelle, i trigger e le tabelle della cronologia non devono essere scritti a mano, ma generati, il che risolverà il problema su come mantenerli "aggiornati".
Doc Brown

Risposte:


5

Conosco questo come "eliminazione graduale"; semplicemente contrassegnando un record come "cancellato", anche se in realtà non lo è.

È una buona pratica o una cattiva pratica?

Dipende.
Se questo è qualcosa di cui i tuoi utenti hanno bisogno [molto], probabilmente è una buona cosa. Nella stragrande maggioranza dei casi, tuttavia, direi che sta aggiungendo [un sacco di] spese generali per un piccolo vantaggio.

Influisce sulla normalizzazione dei dati?

No, ma sarà influenzare l'indicizzazione di tali dati.
Assicurati di includere la colonna "eliminata" nei tuoi indici, in modo che queste righe vengano escluse il prima possibile nelle tue query.

Quali sono le potenziali insidie?

I tuoi dati diventano un po 'più complessi. Tutto ciò che va vicino ai dati deve "conoscere" questi record extra "non proprio lì". In alternativa, devi creare visualizzazioni su quelle tabelle che escludono queste righe e utilizzarle, ad esempio, nel tuo strumento di reporting preferito.

Le dimensioni del database potrebbero aumentare. Se non stai davvero cancellando queste righe, allora sono ancora lì, occupando spazio. Questo potrebbe essere o non essere un problema, soprattutto perché li hai inclusi nei tuoi indici, quindi lo spazio che consumano viene moltiplicato.

Esiste un metodo alternativo per raggiungere lo stesso obiettivo? (Vedi nota)

Non proprio no.

Come si può fare in modo che il database imponga vincoli univoci sui dati solo per un determinato stato (ma consentire un numero qualsiasi di duplicati per altri stati)?

Non facilmente. L'integrità referenziale dichiarativa (clausole di chiave esterna) è il modo più pulito per implementare questo ed è facile per cose come gli strumenti di reporting raccogliere queste regole per determinare le relazioni tra le tabelle. Tali regole si applicano a tutti i record, indipendentemente dallo "stato" (e non c'è modo di aggirarlo).

L'alternativa è usare Trigger, frammenti di codice procedurale che impongono l'integrità referenziale tra le tabelle e fanno tutte le cose intelligenti e condizionate di cui hai bisogno. Va bene per il tuo caso particolare, ma la maggior parte dei vantaggi del RI dichiarativo esce dalla finestra - non ci sono relazioni [esternamente] rilevabili tra i tuoi tavoli; è tutto "nascosto" nei trigger.

Perché i database non forniscono una funzionalità simile al "cestino" o il rilevamento / recupero della tabella in modo nativo, in modo che possiamo consentire alle interfacce di eliminare i record effettivi senza preoccupazioni?

Perché dovrebbero ?

Dopotutto questi sono database, non file system o fogli di calcolo.

Ciò che fanno, [possono] fare molto, molto bene.

Quello che non fanno, probabilmente non c'è stata molta richiesta.


Buona risposta, ma ci sono opzioni alternative, ad esempio spostare le righe in una tabella di backup da cui è possibile recuperarle. La tabella di backup può avere indici minimi. Questo riduce al minimo i problemi che noti con l'approccio esistente (indice più ampio, potenziale confusione per gli utenti della tabella, ecc.), Ma ovviamente aggiunge il fatto che hai un'altra tabella da mantenere (e significa che le voci sono state scritte su riferimenti a chiave esterna). Ci sono alcune altre opzioni, ma in effetti quelle che vengono in mente sono tutte implementazioni personalizzate, non qualcosa di generale fornito da ogni database SQL per questi casi.
Frank Hopkins,

9

È una pratica. Se è buono o cattivo dipende molto dalla tua applicazione e da quanto comunemente avrai davvero bisogno / vuoi fare un "ripristino". Sarei piuttosto dubbioso di un piano per mettere quel tipo di colonna di ogni tabella nel sistema - sembra altamente improbabile che ti preoccupi davvero di implementare il ripristino su ogni tabella del sistema. E richiede l'implementazione: nella stragrande maggioranza dei casi, non stai eliminando una singola riga da una singola tabella, devi attraversare le tabelle secondarie deselezionando le righe e aggiornando le tabelle correlate.

Per la maggior parte delle altre domande, dipende fortemente dall'implementazione. Ad esempio, Oracle offre diversi metodi per tenere traccia di tutte le modifiche a una tabella: Flashback Data Archive (FDA noto anche come Total Recall) è l'approccio più recente per mantenere una cronologia completa di ogni versione di una riga e l'archiviazione nel database per l'implementazione il modello di eliminazione graduale. Altri database possono fornire altri modi per implementare il modello. A seconda del database e di come si implementa l'eliminazione soft, ci saranno vari impatti sulle prestazioni, se e come i vincoli possono essere applicati, ecc. Se stiamo parlando di Oracle, puoi fare molto con indici basati su funzioni, ad esempio , in SQL Server è spesso possibile utilizzare indici filtrati per scopi simili.


Oracle Flashback è esattamente la soluzione ideale per quello che voglio. Peccato che sia di proprietà di Oracle.
ADTC

4

È molto comune utilizzare un campo "contrassegnato per l'eliminazione" nei sistemi MRP / ERP.

Ad esempio, si potrebbe voler contrassegnare una parte o un record di inventario che non viene più venduto come inattivo, ma sono ancora associati ordini in sospeso. Effettuare una vera eliminazione nel record potrebbe influire sugli ordini che non sono stati ancora spediti, sulle voci del libro mastro che non sono ancora state registrate, sulle tabelle cronologiche che non verranno costruite fino alla fine del mese, ecc. Molti sistemi non consentiranno la cancellazione di un record a meno che non passi una serie di convalide rispetto ad altre tabelle. Se stai eliminando a cascata le tue relazioni, una vera eliminazione può essere ancora più distruttiva.

Invece, contrassegnandolo per l'eliminazione, si mette un chiaro indicatore di intenti sul record e successivamente un'attività pianificata può eliminare il record se verifica che tutte le tabelle correlate non lo facciano più riferimento.

Un caso simile potrebbe essere fatto per questa funzione su una tabella clienti e altre tabelle "a lungo termine". Ha persino senso su tabelle più volatili come gli ordini, anche se il nome della bandiera può diventare qualcosa di simile a "spedito" o "annullato". Svolge la stessa funzione: non eliminarlo in questo secondo, ma utilizzalo come flag per il programma di eliminazione, in modo che tenti di convalidare la cancellazione del record in futuro.


3

Come soluzione alternativa, l'uso del sourcing di eventi consente obiettivi simili senza complicare la struttura della tabella, sebbene renda il codice per modificare i dati un po 'più complesso, poiché è necessario scrivere la modifica in un evento che può essere mantenuto in una cronologia degli eventi . Ciò consente quindi di ricreare il database com'era in qualsiasi momento, il che può essere una funzione molto utile.

(Non credo che questo sia ciò che intendevi per "tabella cronologica", che penso intendevi semplicemente copiare i record modificati o eliminati in un'altra tabella prima di cambiarli)


Concetto interessante. Esaminerò come questo può essere implementato.
ADTC

1

Vedo e utilizzo questo schema frequentemente per questi casi d'uso:

  • metadati in cui si desidera visualizzare solo i valori in vigore oggi. Ad esempio, selezionare da un elenco di produttori di auto in un elenco a discesa dove abilitato = 1 i valori delle tabelle per ID, VALUE, ENABLED sono 1, 'Ford', 1 e 2, 'Edsel', 0, 3, 'Toyota' , 1 indica solo le scelte di Ford e Toyota
  • per un sistema di gestione dei casi in cui il paradigma è che un caso può essere solo in uno stato alla volta. In questo caso la colonna di commutazione è stata chiamata CORRENTE con valori di 0 o 1 applicati da vincoli di controllo. Quando un caso si sposta da uno stato a un altro, l'applicazione aggiorna il flag CORRENTE del vecchio stato a 0 e il nuovo a 1

Il problema è applicare l'integrità dei dati se più di un'applicazione o di un servizio Web sta scrivendo su tabelle. Come assicurate che per un caso vi sia un solo stato attuale? Come sottolinea Justin Cave, ciò può essere fatto in Oracle creando un indice virtuale basato su una funzione, ma questo sovraccarico extra per quello che originariamente sembrava un semplice concetto.


1

È una buona pratica se prevedi di utilizzare i tuoi dati per i rapporti (qualsiasi applicazione abbastanza grande dovrebbe avere rapporti).

Al fine di velocizzare la tua applicazione, non dovresti davvero consentire agli strumenti di reporting di essere eseguiti sul tuo database. Pertanto, è necessario eseguire una copia / sincronizzazione con un altro database.

Uso recordStatussolo due stati ACTIVEo CANCELLEDin combinazione con un lastUpdatedOntimestamp. Uso recordStatuspiuttosto statusche di solito ha un significato commerciale.

Quando sincronizzo il database di report con l'applicazione, faccio un filtro lastUpdatedOnper sapere quali sostituirò sul lato del reporting.

Per quanto riguarda la segnalazione, non avrò i campi recordStatuso lastUpdatedOnpoiché in genere non verrà segnalato. Di conseguenza, quando vedo uno CANCELLEDstato, eliminerei il record dal lato del report in modo tale che contenga solo record attivi.

Questo può essere esteso ad altri tipi di negozi come archivi o backup in cui è richiesta una sincronizzazione quasi completa. Tuttavia, la segnalazione è lo scopo più comune.

Nota il tuo esempio di Approved, New, Pendingnon è una buona idea mettere come un campo comune come che ha un business che significa che dovrebbe andare solo dove fa senso degli affari saggia.

Per quanto riguarda il blocco, utilizzare versionNoquale fornisce un blocco ottimistico per il record.

Un'altra opzione invece recordStatusè è recordActivee lo ha memorizzato come uno booleanche occupa meno spazio e meno indicizzazione, ma sarei preoccupato per le esigenze future che potresti non prevedere.

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.