Tipo di dati per la memorizzazione di una matrice di flag (una matrice bitmap / bit)


15

Ho bisogno di memorizzare un array di bit per ogni record di una tabella, supportando le seguenti operazioni:

  • Verifica se è impostato un bit e impostazione di un bit (utilizzando SQL)

  • Interrogazione e impostazione del valore tramite ADO 2.8 (non ADO.NET)

  • Indicizzazione (per beneficiare della funzione "indice di copertura")

Il numero massimo di bit da memorizzare in questo array è fisso, ma può superare 32 . Cioè, una semplice colonna int non funziona sempre.

Da quello che ho visto finora, le mie opzioni sono:

  1. Usa diverse colonne int
  2. Usa bigint (funziona fintanto che il numero di bit è <= 64)
  3. Usa binario
  4. ?

La prima opzione funzionerebbe, ma richiederebbe un po 'di refactoring nel codice che accede ai dati. La seconda opzione è solo un sollievo temporaneo, e dalle mie ricerche finora non sono troppo sicuro se ADO funzioni così bene con bigint . Non ho esperienza con il binario e non sono a conoscenza di altre opzioni.

Quale tipo di dati sceglieresti, dati i requisiti?

Risposte:


12

Non posso sostenere abbastanza fortemente non usare un solo campo per questo.

Attualmente mi occupo di mantenere un set di dati molto grande con a bigint campo maschera di bit ed è un po 'un incubo di prestazioni.

Se controlli un singolo bit, va bene. Se si controlla più di un bit, le prestazioni diminuiscono molto rapidamente.

A causa della natura degli interi con maschera di bit, la distribuzione dei dati sarà molto sbilanciata e otterrai piani non ottimali.

I controlli di bit multipli comportano scansioni di intervallo o indice con una funzione in esecuzione su ogni riga. È un casino.

La mia soluzione era semplice: ho creato un tavolo per memorizzare il PK per ciascuna delle condizioni da verificare. Inizialmente non è intuitivo, ma lo spazio necessario è ridotto (si memorizza solo il PK) e le ricerche sono velocissime, soprattutto se si utilizza a UNIQUE CLUSTERED INDEX.

Puoi aggiungere tutte le condizioni che desideri senza influire sulla tabella principale e anche gli aggiornamenti non influiscono sulla tabella principale.

L'indicizzazione è semplice poiché è sufficiente indicizzare tutte le tabelle di ricerca singolarmente e poiché la chiave cluster è la stessa sulla tabella principale e le ricerche sono tutte le valutazioni merge joinmolto efficienti.


1
Potresti approfondire un po 'di più la tua soluzione? Ho trovato questo perché sto cercando di risolvere lo stesso problema di base, ma non sono sicuro del modo migliore per farlo.
Joshua Frank,

4

Se tutto ciò che serve per memorizzare è un numero moderato di valori vero / falso, è possibile utilizzare il bittipo di dati.

Internamente, SQL Server archivia le bitcolonne impacchettate in "blocchi" di byte. Quindi per un massimo di 8 bitcolonne nella tabella, SQL lo memorizza come 1 byte compresso; 9-16 bitcolonne in 2 byte e così via.

Non sembra che ti avvicinerai al limite della colonna, quindi questo sembra piuttosto semplice. E ovviamente, tenerli ben separati in questo modo ti consente di nominare le colonne per la leggibilità e ottenere tutte le possibilità di indicizzazione normalmente (se i flag sono altamente selettivi, gli indici filtrati possono essere utili se puoi scegliere come target 2008+).

Fare il bit packing da soli renderà molto più complicato fare l'indicizzazione (probabilmente bitcolonne calcolate e indicizzate per rappresentare ogni posizione della maschera ... ma poi stai peggio rispetto all'utilizzo bitdiretto).

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.