Flag vs tabella divisa


10

Sto progettando una tabella di articoli che conterrà (potenzialmente) decine di milioni di record. Alcuni articoli non saranno disponibili per l'uso fino a quando non saranno "approvati" dall'amministratore. Per "uso" intendo che tali articoli non verranno citati in nessun'altra tabella fino a quando non saranno "approvati". Fino al 50% degli articoli può essere "non approvato" in qualsiasi momento. I record possono essere "approvati", ma non viceversa.

Considero due opzioni di progettazione:

  • un po 'di bandiera
  • una tabella separata di articoli "non approvati": quando l'articolo viene approvato, viene spostato nella tabella "normale" (il rinnovo dell'ID dell'articolo non è un problema)

Penso che la seconda opzione sia molto migliore. Il flag di bit richiede solo un byte per riga, quindi non è un problema. Ma se nella stessa tabella sono presenti un milione di record approvati e un milione di record non approvati, il tempo di scansione aumenta per le operazioni con record approvati.

La domanda è: dovrei considerare invece la prima opzione (bit flag)? Ha dei benefici nella situazione descritta?


1
Può essere utile ricordare che è possibile utilizzare gli indici filtrati per accelerare l'accesso ai record approvati. brentozar.com/archive/2013/11/…
mendosi

Sfortunatamente gli indici filtrati non vengono utilizzati nelle query con parametri.
Dima,

@Dima non è del tutto vero. Se un indice filtrato ha detto WHERE status='A'e una query ha WHERE status = 'A' AND (... other columns and parameters here...), allora l'indice potrebbe ancora essere usato.
ypercubeᵀᴹ

Risposte:


6

Puoi averlo in entrambi i modi con viste partizionate .

Si crea una tabella sottostante per ogni stato, imposta da vincoli, con valori reciprocamente esclusivi. Quindi una vista che UNIONE riunisce le tabelle sottostanti. È possibile fare riferimento esplicito alla vista o a ciascuna tabella di base. Se lo stato di una riga è AGGIORNATO nella vista, il DBMS lo eliminerà da una tabella di base e lo inserirà in quello corrispondente al nuovo stato. Ogni tabella di base può essere indicizzata in modo indipendente in base al suo modello di utilizzo. Se possibile, l'ottimizzatore risolverà i riferimenti di indice a una singola tabella di base corrispondente.

I vantaggi sono
a) indici meno profondi. Fai i calcoli sul fan-out dell'indice, tuttavia. A quella scala e diviso tra i valori di stato è possibile che gli indici abbiano la stessa profondità sulle tabelle divise come sarebbero sulla tabella combinata.
b) nessun codice dell'applicazione deve cambiare. I dati continuano ad apparire come un insieme continuo.
c) i nuovi valori di stato futuri possono essere inclusi aggiungendo una nuova tabella di base, con vincolo e ricreando la vista.

Il costo è tutto quel movimento di dati; due pagine e gli indici associati vengono scritti per ogni aggiornamento di stato. Un sacco di IO da affrontare. Questo movimento causerà anche la frammentazione.


5

una tabella di articoli che conterrà (potenzialmente) decine di milioni di record.

In realtà non è molto, dato ciò che SQL Server può gestire in modo efficiente. Certo, ricordo uno dei miei precedenti lavori in cui una delle tabelle più grandi (un sistema a istanza singola) aveva 2 milioni di righe e questo era il massimo che mi fosse mai capitato di fare. Quindi il lavoro successivo ha avuto 17 istanze di produzione con alcune tabelle con centinaia di milioni di righe e tutte sono state aggregate in un data warehouse con più tabelle dei fatti con oltre 1 miliardo di righe. Non fraintendetemi, non sto scherzando su decine di milioni di righe, sto solo sottolineando che con un buon modello di dati e una corretta indicizzazione (e manutenzione dell'indice), SQL Server può gestire molto .

Fino al 50% degli articoli può essere "non approvato" in qualsiasi momento.

Hmm. Non suona bene. Il tasso di "approvazione" delle voci sarà la metà del tasso di ottenere nuove voci? Per ogni 2 nuove voci, solo 1 sarà "approvato"? Nel tuo esempio di 2 milioni di righe e 1 milione ciascuno per "approvato" e "non approvato", qualche anno dopo con altri 10 milioni di voci, ti aspetti 6 milioni ciascuno per "approvato" e "non approvato"? O è che 1 milione di "non approvati" rimarrà in qualche modo costante, in modo tale che con 10 milioni di nuove voci, ci saranno 11 milioni di "approvati" e ancora 1 milione "non approvati"?

I record possono essere "approvati", ma non viceversa.

Questo è vero oggi , ma le cose cambiano nel tempo e quindi c'è sempre la possibilità che l'azienda possa decidere di consentire "non approvazione", o forse qualche altro stato, come "archiviato", ecc.

Quindi, diamo un'occhiata alle scelte:

Flag (o eventualmente anche TINYINT"status")

  • Leggermente più lento per le query di ogni stato
  • Più flessibile nel tempo / facile incorporare una modifica come un terzo stato (ad esempio "Archiviato") con solo un nuovo valore di stato di Ricerca. Nessuna nuova tabella (necessariamente), qualche nuovo codice, solo un po 'di codice aggiornato.
  • Meno lavoro (ad es. Codice, test, ecc.) E meno spazio per errori nell'aggiornamento di una singola TINYINTcolonna
  • Meno complicato = minori costi di manutenzione nel tempo, tempi di formazione più brevi per i nuovi dipendenti da capire
  • (possibilmente) Impatto minore sul registro delle transazioni con l'aggiornamento di una tabella
  • Ho solo bisogno di una tabella di ricerca per "RecordStatus" e FK tra le due tabelle.

Due tabelle separate (una per "approvato", una per "non approvato")

  • Leggermente più veloce per le query di ogni stato
  • Meno flessibile nel tempo / più difficile da integrare un cambiamento come un terzo stato (ad esempio "Archiviato"); il nuovo stato richiederebbe molto probabilmente un'altra tabella e sicuramente un codice nuovo e aggiornato.
  • Più lavoro (ad es. Codice, test, ecc.) E più spazio per errori nello spostamento dei record dalla tabella "Non approvata" alla tabella "Approvata"
  • Più complicato = maggiori costi di manutenzione nel tempo, tempi di formazione più lunghi per i nuovi dipendenti da capire
  • (possibilmente) Maggiore impatto sul registro delle transazioni quando una tabella viene eliminata e una inserita
  • Non è necessario preoccuparsi del " rinnovo dell'ID articolo ": la tabella non approvata ha una colonna ID che è una IDENTITYcolonna e la tabella approvata ha una colonna ID che non è un IDENTITY(in quanto non è necessaria lì). Quindi i valori ID rimangono coerenti quando i record si spostano tra le tabelle.

Personalmente, mi spingerei verso il singolo tavolo con StatusIDcolonna per cominciare. L'uso di due tabelle sembra un'ottimizzazione prematura troppo complicata. Questo tipo di ottimizzazione può essere discusso se / quando il numero di record è in diverse centinaia di milioni e l' indicizzazione non fornisce alcun miglioramento delle prestazioni.


È una tabella con dati in rapido movimento: abbastanza spesso popolata da molte nuove righe, abbastanza spesso le righe vengono eliminate. Ho cercato di rimuovere tutti i dettagli (come decisione aziendale, codifica client, ecc.) Per concentrarmi solo su un singolo argomento. Fondamentalmente abbiamo il tavolo del vecchio design con un po 'di bandiera. E so per il 100% che le righe in cui il flag è impostato su 1 non vengono mai utilizzate in nessun'altra tabella. Quindi sento che si svolgono solo lì e possono essere spostati in un tavolo separato. La tabella viene scansionata quasi su ogni query nel DB. Quindi ridurre il suo "peso" potenzialmente può ridurre le operazioni CPU / IO.
Dima,

3
Un altro vantaggio delle tabelle divise: è possibile avere FK che fanno riferimento solo alla tabella "Approvata".
ypercubeᵀᴹ

L'altro problema con le tabelle divise per una singola entità è l'integrità del vincolo. I riferimenti da altri tavoli non funzioneranno bene con il disco che si muove. Ciò richiederà la scrittura di codice per aggirare questi problemi come le tabelle di riferimento del mirror per la tabella divisa -> Molto problematica
user1567453
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.