Risposte:
Questa è una "domanda d'esame / colloquio" molto comune. Risponderò nel miglior modo possibile:
Nei formati di riga standard per InnoDB e MyISAM (dinamico / compatto) a VARCHAR(50)
e a VARCHAR(255)
memorizzeranno il testo della stringa nello stesso modo: 1 byte per la lunghezza e la stringa effettiva con tra 1 e 4 byte per carattere (a seconda della codifica e il personaggio reale memorizzato).
In effetti, se ricordo bene, ricordo qualcuno che modificava il dizionario dei dati con un editor esadecimale al fine di cambiare qualcosa come un VARCHAR(50)
in un VARCHAR(100)
, in modo che potesse essere fatto in modo dinamico (normalmente, ciò richiede una ricostruzione della tabella). E ciò è stato possibile, poiché i dati effettivi non sono stati influenzati da tale modifica.
Questo non è vero VARCHAR(256)
, perché quindi sono sempre necessari 2 byte (almeno) per la lunghezza.
Quindi, ciò significa che dovremmo sempre fare VARCHAR(255)
, no? No. Ci sono diverse ragioni.
Sebbene InnoDB possa memorizzare un varchar in modo dinamico, ciò non è vero per altri motori. MyISAM ha un formato di dimensione di riga fissa e le tabelle MEMORY sono sempre di dimensioni fisse. Dovremmo preoccuparci di quegli altri motori? Sì, perché, anche se non li utilizziamo direttamente, le tabelle MEMORY sono molto comunemente utilizzate per risultati intermedi (tabelle temporanee in memoria) e poiché i risultati non sono noti in anticipo, la tabella deve essere creata con la dimensione massima possibile - VARCHAR(255)
se questo è il nostro tipo. Se riesci a pensare allo spazio sprecato, se stiamo usando la 'utf8' charset
codifica di MySQL , MEMORY riserverà 2 byte per la lunghezza + 3 * 255 byte per riga(per valori che possono richiedere solo pochi byte su InnoDB). Questo è quasi 1 GB su un milione di tavoli, solo per VARCHAR. Non solo questo causa stress della memoria non necessari, ma può provocare le azioni da eseguire sul disco, rallentandolo potenzialmente migliaia di volte. Tutto ciò a causa di una scarsa selezione del suo tipo di dati definito (indipendentemente dal contenuto).
Ha alcune conseguenze anche per InnoDB. La dimensione dell'indice è limitata a 3072 byte e gli indici a colonna singola, a 767 byte *. Quindi, è molto probabile che non sarai in grado di indicizzare completamente unVARCHAR(255)
campo (supponendo che tu usi utf8 o qualsiasi altra codifica a lunghezza variabile).
Inoltre, la dimensione massima della riga in linea per InnoDB è mezza pagina (circa 8000 byte) e i campi di lunghezza variabile come BLOB o varchar possono essere archiviati fuori pagina se non si adattano alla mezza pagina . Ciò ha delle conseguenze sulle prestazioni (a volte buone, a volte cattive, a seconda dell'uso) che non possono essere ignorate. Ciò ha causato una certa stranezza tra i formati COMPACT e DYNAMIC. Vedere, ad esempio: errore 1118: dimensione della riga troppo grande. utf8 innodb
Ultimo ma non meno importante, come mi ha ricordato @ypercube, potrebbe essere necessario più di 1 byte per la lunghezza anche se si sta utilizzando VARCHAR(255)
, poiché la definizione è in caratteri, mentre la lunghezza memorizza i byte. Ad esempio REPEAT('ñ', 255)
ha più di 2 ^ 255 byte in utf8, quindi richiederebbe più di 1 byte per memorizzarne la lunghezza:
mysql> SELECT LENGTH(REPEAT('ñ', 255));
+---------------------------+
| LENGTH(REPEAT('ñ', 255)) |
+---------------------------+
| 510 |
+---------------------------+
1 row in set (0.02 sec)
mysql> SELECT CHAR_LENGTH(REPEAT('ñ', 255));
+--------------------------------+
| CHAR_LENGTH(REPEAT('ñ', 255)) |
+--------------------------------+
| 255 |
+--------------------------------+
1 row in set (0.00 sec)
Quindi il consiglio generale è quello di utilizzare il tipo più piccolo possibile , perché altrimenti può potenzialmente creare problemi di prestazioni o di gestione. A VARCHAR(100)
è migliore di VARCHAR(255)
(anche se a VARCHAR(20)
sarebbe meglio), anche se non si conosce la lunghezza esatta. Cerca di essere prudente perché, a meno che la tabella non sia troppo grande, puoi sempre modificare la definizione in un secondo momento.
Aggiornamento: poiché l'esplosiva popolarità delle stringhe a lunghezza variabile, ad esempio, con l'uso di emoji, Oracle ha cercato di migliorare le prestazioni in questi casi. Nelle ultime versioni di MySQL (5.6, 5.7), InnoDB è stato impostato come motore predefinito per le tabelle temporanee sia intrinseche che esplicite, il che significa che i campi a lunghezza variabile sono ora cittadini di prima classe. Ciò significa che potrebbero esserci meno motivi per avere lunghezze di carattere molto limitate (ma esistono ancora).
(*) Secondo aggiornamento : large_prefix_index è ora abilitato per impostazione predefinita sulle ultime versioni di MySQL (8.0), ma ciò è ancora vero per le versioni precedenti o se si utilizzano formati di file / righe innodb lagacy (diversi da quelli dinamici o compressi), ma ora per impostazione predefinita, gli indici a colonna singola possono essere fino a quei 3072 byte.
Dimentica il prefisso 1- versus 2 byte su VARCHARs
.
La domanda su 255 è stata posta e ha risposto più volte.
VARCHARs
possono portare al fallimento di CREATE TABLE
.MEMORY
tabelle, con VARCHARs
trasformate in VARCHAR
. Ciò significa, ad esempio, che VARCHAR(255) CHARACTER SET utf8mb4
richiede una lunghezza fissa di 1020 byte. (Questo fallirà e degenererà nell'uso di MyISAM.)In conclusione: non usare ciecamente 255 (o 256); fare ciò che ha senso per lo schema.