2010-12-26 8 views
6

Ho visto alcuni approcci possibili (in alcuni motori di database alcuni di loro sono sinonimi):Qual è il modo ottimale per memorizzare i valori binari/valori booleani in ogni motore di database?

  1. TINYINT (1)
  2. BOOL
  3. BIT (1)
  4. ENUM (0,1)
  5. CHAR (0) NULL

Tutti i principali motori di database supportato da PHP va notato, ma solo come un refference sarà ancora meglio se anche O i motori saranno annotati.

Sto chiedendo un design che sia ottimizzato per la lettura. ad es. SELEZIONARE con il campo flag nella condizione WHERE o GROUP BY the flag. Le prestazioni sono molto più importanti dello spazio di archiviazione (tranne quando le dimensioni hanno un impatto sulle prestazioni).

E qualche dettaglio in più:

Durante la creazione del tavolo non posso sapere se sarà scarsa (se la maggior parte delle bandiere sono on o off), ma posso alterare le tabelle più avanti, quindi se c'è è qualcosa che posso ottimizzare se lo so, dovrebbe essere notato.

Inoltre, se è possibile fare una differenza se c'è un solo flag (o pochi) per riga, rispetto a molti (o molti) flag deve essere notato.

BTW, ho letto da qualche parte nel SO seguente:

Utilizzando booleana può fare la stessa cosa come utilizzando tinyint, tuttavia ha il vantaggio di semanticamente trasmettere ciò che la vostra intenzione è, e quello è vale qualcosa.

Bene, nel mio caso non vale niente, perché ogni tabella è rappresentata da una classe nella mia applicazione e tutto è esplicitamente definito in classe e ben documentato.

risposta

6

Questa risposta è per SQL standard ISO/IEC/ANSI e include i migliori SQL pretend-freeware.

Primo problema: hai identificato due categorie, non una, quindi non possono essere confrontate in modo ragionevole.

A. Categoria Uno

(1) (4) e (5) contengono più valori possibili e sono una categoria. Tutto può essere facilmente ed efficacemente utilizzato nella clausola WHERE. Hanno la stessa memoria, quindi né la memoria né le prestazioni di lettura sono un problema. Pertanto la scelta rimanente si basa semplicemente sul tipo di dati effettivo per lo scopo della colonna.

ENUM non standard; il metodo migliore o standard consiste nell'utilizzare una tabella di ricerca; quindi i valori sono visibili in una tabella, non nascosti e possono essere enumerati da qualsiasi strumento di report. Le prestazioni di lettura di ENUM subiranno un piccolo problema a causa dell'elaborazione interna.

B. Categoria Due

(2) e (3) sono due valori elementi: Vero/Falso; Maschio femmina; Morto vivo. Quella categoria è diversa dalla categoria uno. Il trattamento sia nel modello di dati che in ogni piattaforma è diverso. BOOLEAN è solo un sinonimo di BIT, sono la stessa cosa. Legalmente (SQL-saggio) ci sono gestiti lo stesso da tutte le piattaforme compatibili con SQL, e non ci sono problemi nell'utilizzarlo nella clausola WHERE.

La differenza di prestazioni dipende dalla piattaforma. Sybase e DB2 comprano fino a 8 bit in un byte (non che lo storage contenga qui) e mappano la power-of-two al volo, quindi le prestazioni sono davvero buone.Oracle fa cose diverse in ogni versione, e ho visto i modellisti usare CHAR (1) invece di BIT, per superare i problemi di prestazioni. La SM andava bene fino al 2005, ma l'hanno interrotta con il 2008, poiché i risultati sono imprevedibili; quindi la risposta breve potrebbe essere quella di implementarlo come CHAR (1).

Naturalmente, il presupposto è che non si fanno cose stupide come pacchetto di 8 colonne separate in uno TINYINT. Non è solo un grave errore di normalizzazione, è un incubo per i programmatori. Mantieni ciascuna colonna discreta e del tipo di dati corretto.

C. multipli Indicatore & colonne Nullable

Questo non ha nulla a che fare con, ed è indipendente, (A) e (B). Quello che le colonne correggono Datatype è, è separato da quanti ne hai e se è Nullable. Nullable significa (di solito) la colonna è facoltativa. In sostanza non hai completato l'esercizio di modellizzazione o normalizzazione. Le dipendenze funzionali sono ambigue. se completi l'esercizio di Normalizzazione, non ci saranno colonne Nullable, nessuna colonna opzionale; o esistono chiaramente per una relazione particolare, o non esistono. Ciò significa utilizzare la struttura relazionale ordinaria dei sottotipi Supertipo.

Certo, questo significa più tavoli, ma non Null. Enterpise DBMS non ha problemi con più tabelle o più join, è per questo che sono ottimizzati. banche dati normalizzati eseguono molto meglio di quelli denormalizzati o denormalizzato, e possono essere estesi senza "re-factoring'. Si può alleviare l'utilizzo fornendo una visualizzazione per ogni sottotipo.

Se volete maggiori informazioni su questo argomento, guarda Se hai bisogno di aiuto con la modellazione, chiedere a questo question/answer. si prega di una nuova domanda. al vostro livello di interrogatorio, vorrei consigliare che si bastone con 5NF.

D. prestazioni di Null

separatamente, se le prestazioni è importante per te, quindi escludi i valori Null. Ogni colonna Nullable viene archiviata come lunghezza variabile, che richiede un'ulteriore elaborazione per ogni riga/colonna. s usa una gestione "differita" per tali file, per consentire il logging, ecc. per spostare le code pensate senza ostacolare le righe fisse. In particolare, non usare mai colonne di lunghezza variabile (che comprende colonne Nullable) in un indice: che richiede spacchettamento sul ogni accesso.

E. sondaggio

Infine, non vedo il punto in questione essendo un sondaggio. E 'abbastanza giusto che si ottengono risposte tecniche, e anche opinioni, ma i sondaggi sono per gare di popolarità, e la capacità tecnica di responder al SO copre una gamma molto, quindi le risposte più popolari e le risposte più tecnicamente corretto sono a due diversi estremità dello spettro.

+0

Potrebbe includere un link o ulteriori informazioni su come "MS andava bene fino al 2005, ma hanno rotto con 2008, come nei risultati sono imprevedibili" e se si è rotto in 2K8R2 –

+2

@RC. Non ho collegamenti, ho esperienza. Wiki non ne ha ancora sentito parlare. I risultati del contesto specifico sopra, e alcuni altri, non tutti i contesti, sono imprevedibili; se avessi codice che ha funzionato bene nel 2005. Ho pubblicato diverse altre specifiche: rimozione delle pagine di overflow e danneggiamento di tutte le prestazioni sugli indici Clustered, ecc. Sentiti libero di leggerle. Non risolto in Rev 2. Non è possibile che questi elementi vengano corretti fino al Rev 4 almeno. Ci sono voluti MS in 3 anni per fissare il 2005. – PerformanceDBA

1

So che questa non è la risposta che si desidera, ma la differenza è davvero trascurabile in tutti tranne i casi speciali più estremi. E in ogni caso specifico, cambiare semplicemente datatype non sarà sufficiente per risolvere un problema di prestazioni.

Ad esempio, ecco alcune alternative che superano qualsiasi modifica dei tipi di dati in base a un fattore elevato. Ognuno porta con sé un lato negativo, naturalmente.

Se si dispone di 200 flag opzionali e si esegue la query per un massimo di 1-2 alla volta per un numero elevato di righe, si ottengono prestazioni migliori avendo ciascun flag nella propria tabella. Se i dati sono davvero scarsi, questo diventa ancora migliore.

Se si dispone di 200 flag obbligatori e si eseguono solo recuperi di record singoli, è necessario inserirli nella stessa tabella.

Se si dispone di un piccolo gruppo di flag, è possibile comprimerli in una colonna utilizzando una maschera di bit, che è efficiente in termini di spazio di archiviazione, ma non sarà possibile interrogare (facilmente) singoli flag. Ovviamente, questo non funziona quando i flag possono essere NULL ...

Oppure potresti diventare creativo e utilizzare un concetto di "dimensione indesiderata", in cui crei una tabella separata con tutte le 200 bandiere booleane rappresentate come colonne. Crea una riga per ogni combinazione distinta di valori di flag. Ogni riga riceve una chiave primaria autoincrementata, di cui si fa riferimento nel record principale. Voila, la tabella principale ora contiene 1 int, invece di 200 colonne . Paradiso degli hacker, incubo del DBA.

Il punto che sto cercando di fare è che anche se è interessante discutere su quale sia "il migliore", ci sono altre preoccupazioni che hanno un'importanza molto maggiore (come il commento che hai citato). Semplicemente perché quando si verifica un problema di prestazioni reali, il tipo di dati non sarà né il problema né la soluzione.

0

Qualsiasi dei precedenti è soddisfacente e ho una preferenza personale per l'utilizzo di BOOL se è supportato correttamente in quanto ciò trasmette al meglio le tue intenzioni ma eviterei di utilizzare ENUM(0,1).

Il primo problema con ENUM è che richiede che il suo valore sia una stringa. 0 e 1 sembra un numero in modo che i programmatori abbiano la tendenza a inviarlo un numero.

Il secondo problema con ENUM è che se si invia un valore errato, esso è impostato per default alla prima enumerazione e in alcuni database non indicherà nemmeno un errore (sto osservando MySQL). Questo rende il primo problema molto peggiore poiché se lo invii per errore 1 invece di "1", esso memorizzerà il valore "0" - molto contro-intuitivo!

Non penso che questo abbia effetto su tutti i motori di database (non so, non li ha provati tutti) ma ne colpisce abbastanza che ritengo che evitarlo sia una buona pratica.