2015-12-19 18 views
9

Attualmente stiamo ottimizzando una tabella MySQL (InnoDB) che avrà eventualmente oltre 100 milioni di righe.Indice sulla colonna con il 70% di valori vuoti: utilizza valori nulli o vuoti?

In una colonna, stiamo memorizzando gli indirizzi IP (VARCHAR 45). Abbiamo bisogno di mettere un indice su questa colonna, in quanto dobbiamo essere in grado di recuperare tutte le righe per indirizzo IP specifico.

70% di tutte le righe, tuttavia, non memorizzare un indirizzo IP (vuoto).

La nostra domanda: Dobbiamo memorizzare quei valori vuoti come NULL e quindi CONSENTI NULL su questa colonna (aggiungerà 1 byte per ogni riga). Oppure NON AMMETTERE NULL e memorizziamo i valori vuoti come "(stringa vuota)?

Cosa è meglio per le prestazioni?

Non dobbiamo mai cercare le righe vuote (= '') o null (IS NULL), cercare solo indirizzi IP specifici (= '123.456.789.123').

Aggiornamento: ci sono davvero molte domande su SO che affrontano scenari simili. Tuttavia, alcune risposte sembrano contraddittorie o dicono "dipende". Eseguiremo alcuni test e pubblicheremo i risultati per il nostro scenario specifico qui.

+0

Immagino che la stringa vuota sia leggermente più performante purché utilizzi meno spazio di archiviazione. L'indice sarebbe fondamentalmente lo stesso in entrambi i casi. La soluzione migliore è quella che TEST e verifica è più veloce – Grantly

+1

Possibile duplicato di [MySQL: NULL vs ""] (http://stackoverflow.com/questions/1106258/mysql-null-vs) – Shadow

+0

@Shadow Sì, sembra una domanda simile - ma a prima vista mi sembra che le due risposte più alte dicano il contrario? Uno dice "usa null", l'altro dice "non usare null!". –

risposta

2

VARCHAR(39) è sufficiente per entrambi IPv4 (il vecchio formato, per il quale non sono disponibili altri valori) e IPv6.

L'ottimizzatore può rovinarsi se il 70% dei valori è lo stesso ('' o NULL). Ti suggerisco di avere un'altra tabella con l'IP e un ID per ENTRARE alla tua tabella originale. Non avendo IP "vuoti" nella seconda tabella, l'ottimizzatore ha più probabilità di "fare la cosa giusta".

Con ciò, è possibile utilizzare LEFT JOIN per verificare se esiste un IP.

IPv6 può essere memorizzato in BINARY (16) per risparmiare spazio.

+0

Se la seconda tabella non aveva indirizzi IP vuoti, dovresti usare null come chiave esterna, che ti riporta indietro dove hai iniziato. – EJP

+0

Questo è un argomento contro gli FK. Non sono utili in tutte le situazioni. –

+1

@EJP Hai frainteso. Rick sta suggerendo di avere una relazione, in cui il nuovo tavolo ha un riferimento all'originale. Non ci sarebbe alcuna colonna IP o IP_id nella tabella originale. – Arth

0

La differenza principale tra NULL e una stringa vuota è correlata ai valori di confronto . Due stringhe vuote sono considerate uguali. Due valori NULL no. Ad esempio, se si desidera unire due tabelle in base alle colonne valore IP , il risultato sarà abbastanza diverso per le stringhe vuote NULL e e molto probabilmente si desidera il comportamento di NULL.

Se si cercano solo indirizzi IP specifici, l'uso di NULL o stringa vuota non dovrebbe avere importanza. Se la colonna del valore IP è indicizzata, l'ottimizzatore Otterrà una stima da InnoDB sul numero di righe con il valore specifico. In questo caso non verranno utilizzate le statistiche generali sul numero di righe per valore.

Evitando valori NULL si risparmiano 30 MB su 100 milioni di righe quando 70% delle righe sono NULL. (Per le righe in cui il valore è una stringa vuota, non si salverà spazio poiché è necessario un byte per memorizzare le informazioni sulla lunghezza di .Rispetto a ciò che è possibile salvare memorizzando i valori IP come una stringa binaria, questo non è nulla, e non penso che l'overhead di archiviazione sia un problema valido.

+0

Il costo dello spazio dei valori 'NULL' è rilevante solo in MyISAM. InnoDB non ha costi di spazio per 'NULL's. – manchicken

+0

Le intestazioni di riga InnoDB contengono un vettore di bit su colonne che sono NULL. Se non ci sono colonne NULL, l'intestazione della riga non conterrà questo vettore bit. Quindi, una tabella senza colonne NULL utilizzerà 1 byte in meno per riga rispetto alla stessa tabella con 1-8 colonne NULL. Vedi https://dev.mysql.com/doc/refman/5.7/en/innodb-physical-record.html – oysteing

1

Vai con valori NULL. InnoDB non ha costi di spazio per i valori NULL s e NULL esclusi dagli indici, quindi avrai una ricerca indice più rapida per i valori presenti.

Per quanto riguarda il modo in cui si memorizza l'IP stesso (stringa numero di verus), ciò sembra un punto di ottimizzazione molto meno importante.

Problemi correlati