2016-02-14 7 views
11

Sto costruendo un'app mobile Io uso PHP & MySQL per scrivere un backend - API REST.Come memorizzare 60 booleani in un database MySQL?

Se devo memorizzare circa 50-60 valori booleani in una tabella denominata "Report" (gli utenti devono controllare le cose in un modulo) nella mia app mobile, memorizzo i valori (0/1) in un array semplice. Nel mio MySql Table dovrei creare una colonna diversa per ogni valore booleano o è sufficiente se uso semplicemente una stringa o un Int per memorizzarlo come un "numero" come "110101110110111 ..."?

Ottengo e inserisco i dati con JSON.

UPDATE 1: Tutto quello che devo fare è controllare se tutto è 1, se uno di questi è 0 allora questo è un "problema". In 2 anni questa tabella avrà circa 15.000-20.000 file, deve essere molto veloce e il più salvaspazio possibile.

AGGIORNAMENTO 2: In termini di velocità, quale soluzione è più veloce? Creare colonne separate e memorizzarle in un tipo stringa/binario. Cosa succede se devo verificare quali sono gli 0? È un'ottima soluzione se lo memorizzo come "numero" in una colonna e se non è "111..111", quindi inviarlo all'app mobile come JSON dove analizzo il valore e lo analizzo sul dispositivo dell'utente? Diciamo che devo occuparmi di 50K righe.

Grazie in anticipo.

+2

Se è necessario eseguire una ricerca (utilizzando elementi come 'WHERE bool_a AND NOT bool_b') sui valori di questi flag, questo ti spinge a memorizzarli nelle proprie colonne. Ma non ci hai detto come la tua applicazione ha bisogno di usare questi dati. –

+0

Hai ragione. Tutto quello che devo fare è controllare se tutto è 1, se uno di questi è 0, allora è un "problema". In 2 anni questa tabella avrà circa 15.000-20.000 file, deve essere molto veloce e il più salvaspazio possibile. – nethuszar

+0

Puoi andare con le bandiere, se sei sicuro al cento per cento non devi aggiungere cose nel mezzo. Puoi usare il tipo BINARY per quello. – MartijnK

risposta

13

Una colonna separata per valore è più flessibile quando si tratta di cercare.

Una tabella chiave/valore separata è più flessibile se diverse righe hanno raccolte diverse di valori booleani.

E, se

  1. tua lista di valori booleani è più o meno statico
  2. tutte le righe hanno tutti quei valori booleani
  3. la ricerca delle prestazioni critiche è quello di trovare righe in cui uno qualsiasi dei valori è falso

quindi utilizzare stringhe di testo come "1001010010" ecc. è un buon modo per memorizzarle. Puoi cercare in questo modo

WHERE flags <> '11111111' 

per trovare le righe che ti servono.

È possibile utilizzare una colonna BINARY con un bit per flag. Ma il tuo tavolo sarà più facile da usare per le query casuali e l'ispezione del bulbo oculare se usi il testo. Il risparmio di spazio derivante dall'utilizzo di BINARY anziché di CHAR non sarà significativo finché non inizierai a memorizzare molti milioni di righe.

modifica Si deve dire: ogni volta che ho costruito qualcosa di simile con matrici di attributi booleani, in seguito sono stato deluso da quanto si è rivelato inflessibile. Ad esempio, supponiamo che fosse un catalogo di lampadine. Al volgere del millennio, le bandiere booleani avrebbero potuto essere roba come

screw base 
halogen 
mercury vapor 
low voltage 

Poi, le cose cambiano e mi trovo a dover più flag booleani, come,

LED 
CFL 
dimmable 
Energy Star 

ecc Tutto ad un tratto i miei tipi di dati non sono abbastanza grandi da contenere ciò che ho bisogno di loro.Quando ho scritto "il tuo elenco di valori booleani è più o meno statico" intendevo dire che non ti aspetti ragionevolmente che qualcosa come le caratteristiche della lampadina cambino durante la vita della tua applicazione.

Quindi, una tabella separata degli attributi potrebbe essere una soluzione migliore per. Avrebbe queste colonne:

item_id   fk to item table   -- pk 
    attribute_id  attribute identifier  -- pk 
    attribute_value 

Questo è in definitiva flessibile. Puoi solo aggiungere nuove bandiere. Puoi aggiungerli a elementi esistenti o a nuovi elementi, in qualsiasi momento nel corso della vita della tua applicazione. E ogni oggetto non ha bisogno della stessa collezione di bandiere. Puoi scrivere "quali elementi hanno attributi falsi?" query come questa:

SELECT DISTINCT item_id FROM attribute_table WHERE attribute_value = 0 

Ma, bisogna stare attenti perché la query "i prodotti a prezzo attributi mancanti" è molto più difficile da scrivere.

+0

Che dire di BIT (N) invece di stringa? –

+0

Grazie per la risposta. "ogni volta che ho costruito qualcosa di simile con array di attributi booleani, sono stato in seguito deluso" Puoi darmi una soluzione migliore? Sono aperto a imparare cose nuove. – nethuszar

+0

Definitivamente una nuova tabella, è anche normalizzata. https://en.wikipedia.org/wiki/Database_normalization#Minimize_redesign_when_extending_the_database_structure –

11

Per lo scopo specifico, quando qualsiasi zero-flag è un problen (un'eccezione) e la maggior parte delle voci (come 99%) sarà "1111 ... 1111", non vedo alcun motivo per memorizzarle tutte. Preferirei creare una tabella separata che memorizza solo le bandiere non selezionate. La tabella potrebbe avere il seguente aspetto: uncheked_flags (user_id, flag_id). In un'altra tabella si memorizzano le definizioni dei flag: flag (flag_id, flag_name, flag_description).

Quindi il rapporto è semplice come SELECT * FROM unchecked_flags.

Aggiornamento - possibili definizioni di tabella:

CREATE TABLE `flags` (
    `flag_id` TINYINT(3) UNSIGNED NOT NULL AUTO_INCREMENT, 
    `flag_name` VARCHAR(63) NOT NULL, 
    `flag_description` TEXT NOT NULL, 
    PRIMARY KEY (`flag_id`), 
    UNIQUE INDEX `flag_name` (`flag_name`) 
) ENGINE=InnoDB; 

CREATE TABLE `uncheked_flags` (
    `user_id` MEDIUMINT(8) UNSIGNED NOT NULL, 
    `flag_id` TINYINT(3) UNSIGNED NOT NULL, 
    PRIMARY KEY (`user_id`, `flag_id`), 
    INDEX `flag_id` (`flag_id`), 
    CONSTRAINT `FK_uncheked_flags_flags` FOREIGN KEY (`flag_id`) REFERENCES `flags` (`flag_id`), 
    CONSTRAINT `FK_uncheked_flags_users` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) 
) ENGINE=InnoDB; 
1

È può ottenere una ricerca migliore di utilizzare colonne dedicate, per ogni booleano, ma la cardinalità è scarsa e anche se indice di ogni colonna interesserà un bel po 'di attraversamento o scansione.

Se stai cercando HIGH-VALUES 0xFFF .... quindi sicuramente bitmap, questo risolve il tuo problema di cardinalità (per aggiornamento OP). Non è come se si stesse controllando la parità ... L'albero sarà comunque fortemente distorto in ALTI-VALORI se questo è normale e può creare un punto caldo incline alla divisione del nodo sugli inserti.

La mappatura dei bit e l'utilizzo di maschere di operatore bit a bit consente di risparmiare spazio ma deve essere allineato a un byte, pertanto potrebbe esserci un "suggerimento" non utilizzato (il provisioning per i campi futuri), pertanto la maschera deve essere di lunghezza mantenuta o il campo riempito con 1s.

Aggiungerà anche complessità alla tua architettura, che potrebbe richiedere una codifica su misura, standard su misura.

È necessario eseguire un'analisi sull'importanza di qualsiasi ricerca (normalmente non si prevede di effettuare una ricerca in tutti i campi o anche in nessuno dei campi discreti).

Questa è una strategia molto comune per denormalizzare i dati e anche per la richiesta di servizi di ottimizzazione per client specifici. (Dove alcune risposte sono più grasse di altre per la stessa transazione).