Vantaggi e svantaggi dell'utilizzo di maschere di bit nel database


22

Non molto tempo fa ho parlato con il mio collega ed era decisamente contrario all'utilizzo di maschere di bit perché è difficile comprendere tutti i valori memorizzati nel database. Secondo me non è sempre una cattiva idea usarli, ad esempio per determinare i ruoli dell'utente corrente. In caso contrario, è necessario memorizzarlo in una tabella separata, che causerà un ulteriore JOIN. Potete per favore dirmi se sbaglio? Altri effetti collaterali, vantaggi / svantaggi dell'utilizzo di maschere di bit?


2
Potrebbe essere più sensato che il database crei maschere di bit internamente e presenti i bit come colonne separate. Le tue esigenze potrebbero cambiare.
Simon Richter,

1
Se non si utilizzano i join, non si utilizza il database relazionale nel modo previsto.
Pieter B,

Risposte:


38

Lavoro con un'applicazione che utilizza maschere di bit per archiviare le assegnazioni di ruoli utente. È un dolore al sedere. Se questo mi rende di parte, colpevole come accusato.

Se stai già utilizzando un database relazionale, si tratta di un anti-pattern che viola la maggior parte della teoria relazionale e tutte le regole di normalizzazione. Quando si crea il proprio archivio dati, potrebbe non essere una cattiva idea.

Esistono troppi tavoli da unire, ma i database relazionali sono costruiti per gestirlo. Molti hanno funzionalità aggiuntive se le prestazioni diventano un problema: indici, viste indicizzate, ecc. Anche se i valori che stai cercando non cambiano molto spesso, il che è un vantaggio per Bitmask, il sovraccarico di dover gestire l'indicizzazione è abbastanza facile sul database.

Sebbene il database faccia un buon lavoro di aggregazione dei dati, possono diventare lenti quando inizi a introdurre elementi come formule complesse o funzioni scalari nei set di dati. Puoi fare bit per bit nella tua app, ma se tutto ciò che stai facendo è ottenere dati correlati (cercare i ruoli di un utente), non stai sfruttando ciò che fa meglio la tua memoria di dati.

Il mio ultimo argomento contro questo sarebbe la semplicità per gli altri sviluppatori. Hai utenti, ruoli e incarichi. È un insieme di relazioni molti-a-molti (perché c'è più di una relazione) così comune, che dovrebbe essere facile da gestire. È solo roba CRUD.


8
Un database relazionale è il posto peggiore per una maschera di bit. I costi di archiviazione non sono più così negativi che alcuni join e un tavolo aggiuntivo dovrebbero spezzarti. Certamente rende tutto più difficile da ragionare. Memorizzare le autorizzazioni come bit (1/0) nel database nella propria tabella e rappresentarle nel codice con ma flag. Sembra abbastanza appropriato e fattibile. Gli sviluppatori ottengono semplici flag e dbas hanno tabelle normalizzate. Sono tutti felici.
Mike McMahon,

3
D'accordo, ero solito supportare un'applicazione che utilizzava maschere di bit per ruoli utente e privilegi nel suo database. È stato un incubo. Usando un int a 32 bit, abbiamo esaurito i bit, quindi qualcuno ha avuto la grande idea di aggiungere più maschere di bit, e quindi con sovrapposizioni, quindi il bit 4 in una colonna significava il bit 8 in quest'altra colonna, e sono usciti dalla sincronizzazione. Sì, sì, sì. È stato difficile indicizzare perché gli indici memorizzano valori di colonna discreti, non i singoli bit in essi contenuti, quindi non è possibile cercare righe where some_bit_mask & 12 > 0senza una scansione riga per riga.
Brandon,

Alla fine della giornata, una relazione molti-a-molti user_role_mapo user_priv_maptavolo sarebbe stato sufficiente.
Brandon,

@MikeMcMahon, potresti per favore approfondire la progettazione della tabella e come dovrei mapparla nel codice per ottenere il risultato di cui stai parlando?
Alex Ovechkin,

2
@usr - Non dire mai mai. Sicuro che puoi usare le maschere di bit, ma non le userei in un'applicazione che utilizza un database relazionale. Probabilmente ci sono alcuni casi limite quando si tratta di dati legacy o una super necessità di velocità.
JeffO,

24

Hai già nominato i relativi pro e contro:

  • I campi di bit risparmiano spazio.
  • Memorizzano i dati nel record stesso, quindi non è necessario JOIN per trovarli. (Ma i singoli campi bandiera nel record farebbero lo stesso.)
  • Sono mal leggibili se si desidera lavorare in modo produttivo con output SQL non elaborato.

Decidere cosa fare richiede maggiori informazioni:

  • Quanto è scarso lo spazio su disco per il tuo caso d'uso?
  • In realtà leggi i ruoli degli utenti così spesso che il tempo di unirti a loro è un collo di bottiglia?
  • Stai andando a leggere decisioni di produzione e rendere SQL in base a tale - o è una base di dati illeggibili record di immateriale, così come il fatto che il codice macchina del sistema è illeggibile?

Quindi, quello che devi fare è raccogliere i fattori di rischio e quindi ponderarli , per vedere se i professionisti superano i contro.


Grazie per la tua risposta, totalmente d'accordo con i tuoi pensieri, ma in generale è questo anti-schema o no? E usi le maschere nei tuoi progetti?
Alex Ovechkin,

12
@Alex Non esiste una "best practice" che possa decidere cosa fare nel tuo caso. Se lo spazio è estremamente ridotto, è consigliabile utilizzare i campi di bit. Se si desidera utilizzare l'output SQL nei report per il CEO, è consigliabile utilizzare nomi vocali. Ma tu sei l'unico che conosce queste circostanze, quindi la comunità non può darti una ricetta sempre valida.
Kilian Foth,

Prendendo l'argomento spazio come "dammi". La questione se utilizzare una maschera di bit si pone o cade sul fatto che offra qualche vantaggio oltre a questo.
Robbie Dee,

Inoltre, OGNI bisogno di elaborare le informazioni nel database o viene sempre letto in un'applicazione prima di utilizzarlo.
Ian,

1
"Hai intenzione di leggere l'output SQL e prendere decisioni basate su questo - o un record di dati illeggibile è irrilevante, proprio come il fatto che il codice macchina del tuo sistema è illeggibile?" Immagino di non poter parlare per tutti gli sviluppatori, ma quando sto sviluppando, è estremamente comune per me iniziare a selezionare i dati dal DB per capire o controllare qualcosa. Quindi direi che di solito la risposta è "Sì, qualcuno lo farà".
jpmc26,

18

Se sei veramente, veramente , veramente a corto di spazio su disco, allora si potrebbe prendere in considerazione bitmap per le autorizzazioni degli utenti. Se la performance è la tua preoccupazione, allora dimenticala del tutto, perché separarli sarà effettivamente più lento. Non è possibile indicizzare in modo significativo un campo bitmap, determinando scansioni della tabella del database, che sono [quasi] sempre un killer delle prestazioni.

A meno che tu non sia Amazon o Netflix, la quantità di dati coinvolti nelle autorizzazioni degli utenti sarà trascurabile rispetto a tutto il resto che hai in mano.

Qualsiasi DBMS serio può gestire quel "join aggiuntivo" senza nemmeno battere ciglio.


7
+1: I buoni database relazionali sono sviluppati da persone che sono davvero molto brave in quello che fanno. Chiunque al livello di necessità di cancellare l'ultimo bit di prestazioni che potresti ottenere utilizzando i campi di bit non dovrebbe porre la domanda. Modella i dati, quindi trova le parti che non eseguono.
Blrfl,

Avere il join renderà il codice dell'applicazione più complesso, quindi molto dipende da DOVE vengono elaborati i ruoli.
Ian,

4
@Ian avere il join non sembra più complesso del bisogno di sapere come decifrare i permessi con maschera di bit.
Brad

@Brad, Pensa a un enum che è un insieme di flag in C #, con il suo valore memorizzato "così com'è" nel database, il freddo di C # non può essere più semplice. Se viene utilizzato un join, il codice C # deve far fronte a una relazione "da 1 a molti".
Ian,

Dovrei anche aggiungere che se hai più colonne booleane in una tabella, la maggior parte dei database capirà come schiacciarle nel minor spazio possibile e si occuperà del bit-twiddling per te.
Blrfl,

8

Ai tempi in cui lo stoccaggio era costoso, il vantaggio con le maschere di bit era che risparmiavano spazio. Ai tempi dei big data, questo non era il problema di una volta.

Prendendo l'esempio che citi: avere ruoli archiviati come maschera di bit sarebbe una sorta di odore di codice dal punto di vista della progettazione del database in quanto violerebbe la prima forma normale . In questo senso, sono un anti-schema.

Detto questo, non deve essere l'uno o l'altro. È possibile archiviare i dati come maschera di bit e quindi avere una vista in grado di estrarre al volo i ruoli utente. Avresti anche il vantaggio di controllare a colpo d'occhio quali utenti avessero gli stessi ruoli.


2

L'unico vantaggio dell'uso delle maschere di bit è se il significato dei campi di bit non è statico. Le tabelle relazionali funzionano bene solo se si sa in anticipo cosa è ogni campo in un record: CREATE TABLEdopo tutto, è necessario identificare i campi nell'istruzione DDL.

Se il significato di ciascun campo di bit è configurabile in fase di esecuzione o altrimenti non è noto in anticipo, potrebbe essere logico archiviare i booleani come campo di bit. Anche allora, è possibile definire una tabella con campi arbitrari: field_1, field_2, ecc Questo vi dà un design relazionale più pulito, anche se non ancora ideale. Se questo sia preferenziale a un piccolo campo è in gran parte una questione di opinione, dal momento che nessuna soluzione è l'ideale.

Se sai cosa rappresentano i bit durante lo sviluppo, quindi crea campi per ciascun bit e dai loro nomi significativi .

Fai solo attenzione all'effetto piattaforma interna . Se finisci per definire campi arbitrari ma ben tipizzati, questo è una cosa, ma se vai troppo oltre, reinventerai un database relazionale ... all'interno di un database relazionale.


2

Sono ambivalente riguardo alle maschere di bit. Trovo che la maggior parte dei loro detrattori non capisca binario ed esadecimale. Per chiarezza, usa una buona mnemonica.

Un vantaggio non menzionato sopra è la possibilità di aggiungere un nuovo significato alle maschere di bit senza l'aggiunta potenzialmente dispendiosa in termini di tempo di una nuova colonna. I nostri designer db (che mi hanno preceduto) li hanno in una tabella che ora ottiene 5 milioni di nuovi record ogni giorno. L'aggiunta di una nuova colonna per rappresentare un nuovo comportamento richiederebbe molto tempo, mentre la definizione di un nuovo bit (ne abbiamo consumati 33 su 64) non richiede la ricostruzione della tabella.

No, le maschere di bit non possono essere indicizzate ma la costruzione di 33 indici sarebbe ridicola e rallenterebbe gli inserimenti in una scansione. Le ricerche di tabella utilizzano le date e registrano gli indici "proprietari", quindi gli indici su questa maschera di bit, se possibile, non verrebbero mai utilizzati.


È un caso interessante. Suppongo che tu possa ottenere lo stesso in modo kosher ed esplicito, definendo le colonne "di riserva" sul tavolo e quindi utilizzandole secondo necessità. È quindi possibile almeno indicizzare queste colonne in modo selettivo, se si sceglie di farlo.
Steve

1

Se l'obiettivo è solo quello di risparmiare spazio su disco, penso che sia una cattiva idea:

  • guarda il costo del GB oggi,
  • confrontarlo con il costo del tempo di coloro che scrivono report e query e devono capire cosa c'è nel campo e come affrontare un bit specifico, il confronto costi / benefici potrebbe finire dalla parte sbagliata.
  • se si lavora con un database SQL, le operazioni di accesso ai bit aggiuntive richieste in molte query potrebbero anche richiedere più tempo di elaborazione del necessario

Tuttavia, ci sono alcuni casi che possono giustificare l'uso dei campi bit:

  • se i tuoi bit rappresentano un insieme complesso di flag che gestisci sempre insieme nel suo insieme,
  • ancora di più se è necessario applicare alcuni algoritmi di corrispondenza dei pattern su questi set,
  • e soprattutto se questi dati non sono tra i criteri di selezione più frequentemente utilizzati.
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.