Implicazioni sulle prestazioni delle dimensioni MySQL VARCHAR


45

C'è una differenza di prestazioni in MySQL tra le dimensioni di varchar? Ad esempio, varchar(25)e varchar(64000). In caso contrario, c'è un motivo per non dichiarare tutti i varchar con la dimensione massima solo per assicurarsi di non rimanere senza spazio?


3
+1 questa domanda si applica in modo simile a tutti i DBMS. La mia osservazione di molte dimensioni varchar tende a crescere.
bernd_k,

5
Non MySQL, ma questo post sul blog di Depesz potrebbe rispondere alla tua domanda per PostgreSQL .
xenoterracide,

Risposte:


29

È necessario realizzare i compromessi dell'utilizzo di CHAR vs VARCHAR

Con i campi CHAR, ciò che assegni è esattamente quello che ottieni. Ad esempio, CHAR (15) alloca e memorizza 15 byte, indipendentemente dal carattere inserito nel campo. La manipolazione delle stringhe è semplice e diretta poiché la dimensione del campo dati è totalmente prevedibile.

Con i campi VARCHAR, ottieni una storia completamente diversa. Ad esempio VARCHAR (15) alloca effettivamente in modo dinamico fino a 16 byte, fino a 15 per i dati e, almeno, 1 byte aggiuntivo per memorizzare la lunghezza dei dati. Se hai la stringa 'ciao' da memorizzare che richiederà 6 byte, non 5. La manipolazione della stringa deve sempre eseguire una qualche forma di controllo della lunghezza in tutti i casi.

Il compromesso è più evidente quando si fanno due cose:
1. Memorizzare milioni o miliardi di righe
2. Indicizzare colonne che sono CHAR o VARCHAR

TRADEOFF # 1

Ovviamente, VARCHAR ha il vantaggio poiché i dati a lunghezza variabile produrrebbero file più piccole e, quindi, file fisici più piccoli.

TRADEOFF # 2

Poiché i campi CHAR richiedono una minore manipolazione delle stringhe a causa della larghezza fissa dei campi, le ricerche dell'indice rispetto al campo CHAR sono in media il 20% più veloci rispetto a quelle dei campi VARCHAR. Questa non è alcuna congettura da parte mia. Il libro MySQL Database Design and Tuning ha eseguito qualcosa di meraviglioso su una tabella MyISAM per dimostrarlo. L'esempio nel libro ha fatto qualcosa di simile al seguente:

ALTER TABLE tblname ROW_FORMAT=FIXED;

Questa direttiva impone ai VARCHAR di comportarsi come CHAR. L'ho fatto nel mio precedente lavoro nel 2007 e ho preso un tavolo da 300 GB e accelerato la ricerca dell'indice del 20%, senza cambiare nient'altro. Ha funzionato come pubblicato. Tuttavia, ha prodotto un tavolo di dimensioni quasi doppie, ma questo risale semplicemente al compromesso n. 1.

È possibile analizzare i dati archiviati per vedere cosa consiglia MySQL per la definizione di colonna. Basta eseguire quanto segue su qualsiasi tabella:

SELECT * FROM tblname PROCEDURE ANALYSE();

Ciò attraverserà l'intera tabella e raccomanderà le definizioni di colonna per ogni colonna in base ai dati in essa contenuti, ai valori minimi dei campi, ai valori massimi dei campi e così via. A volte, devi solo usare il buon senso con la pianificazione di CHAR vs VARCHAR. Ecco un buon esempio:

Se si memorizzano gli indirizzi IP, la maschera per tale colonna è al massimo di 15 caratteri (xxx.xxx.xxx.xxx). Vorrei saltare a CHAR (15) in un batter d'occhio perché la lunghezza degli indirizzi IP non varierà molto e la complessità della manipolazione delle stringhe controllata da un byte aggiuntivo. È ancora possibile eseguire una PROCEDURA ANALISI () su tale colonna. Potrebbe anche raccomandare VARCHAR. In questo caso, i miei soldi sarebbero ancora su CHAR su VARCHAR.

I problemi CHAR vs VARCHAR possono essere risolti solo attraverso un'adeguata pianificazione. Da un grande potere derivano grandi responsabilità (cliché ma vero)


4
Se si memorizzano gli indirizzi IP non vedo alcun motivo per memorizzarli come qualcosa di diverso da un int. Questo è tutto un indirizzo IP. Molte lingue hanno una sorta di funzione ip2int. Se si desidera la comodità di una chiamata da riga di comando, non è difficile creare una procedura memorizzata per convertire ABCD: A pow (256,3) + b pow (256,2) + c * 256 + d
atxdba,

1
Err più al punto che immagino che mysql abbia la sua funzione ip2int: INET_ATON
atxdba,

3
@atxdba: il punto della mia risposta è solo usare CHAR vs VARCHAR. Uso solo IP come esempio perché la sua dimensione del carattere della stringa è più vicina a 15. Pertanto, arrotondare una dimensione CHAR stabile a favore di VARCHAR è solo un esempio per il bene della domanda stessa. Il tuo commento sui modi migliori per rappresentare gli indirizzi IP è abbastanza valido e ha più senso.
RolandoMySQLDBA,

CHAR (15) alloca 15 caratteri , non byte . Per utf8, ovvero 45 byte .
Rick James,

2
Sebbene questa sia una buona risposta sul confronto CHAR / VARCHAR, la domanda riguardava le diverse dimensioni di VARCHAR.
Collezionista

13

La risposta a questa è in realtà piuttosto complessa. La versione breve: c'è una differenza .

  1. Quando si creano tabelle temporanee per filtrare i risultati (ad es. GROUP BYIstruzioni), verrà allocata l'intera lunghezza.

  2. Il protocollo wire (invio di righe al client) probabilmente assegnerà la lunghezza maggiore.

  3. Il motore di archiviazione potrebbe / potrebbe non implementare un varchar adeguato.

Per (2) ammetto che il protocollo wire non è qualcosa che conosco intimamente, ma il consiglio generale qui è provare e applicare almeno un minimo sforzo per indovinare la lunghezza.


Vale la pena sottolineare. MySQL 5.7 può comprimere i valori nel buffer di ordinamento (lunghezza variabile). Spiegato più in dettaglio qui: mysqlserverteam.com/…
Morgan Tocker

9

La maggior parte delle risposte in questo thread hanno 5 anni, scritte prima che InnoDB e utf8 fossero predefiniti. Quindi, lasciami ricominciare ...

Quando una query necessita di una tabella temporanea interna, tenta di utilizzare una MEMORYtabella. Ma MEMORY non può essere usato se

  • TEXT/ BLOBcolonne recuperate, nemmeno TINYTEXT.
  • VARCHAR più grande di una certa quantità, probabilmente 512 nella versione corrente.

Inoltre, si noti che VARCHARsvengono trasformati in CHARs. Quindi, VARCHAR(255)con un si CHARACTER SET utf8espande a 765 byte, indipendentemente da ciò che è nella colonna. Quindi, questo potrebbe essere attivato:

  • Se la MEMORYtabella diventa più grande di una max_heap_table_size o tmp_table_size , verrà convertita in MyISAM e potenzialmente versata su disco.

Quindi, VARCHAR(25)è più probabile che rimanga MEMORY, quindi essere più veloce. (255)non è buono ed (64000)è cattivo.

(In futuro, probabilmente lo saranno le tabelle temporanee InnoDBe parte di questa risposta dovrà essere rivista.)


6

Una colonna varchar di quelle dimensioni rende più probabile che le query sull'intera tabella utilizzino le tabelle temporanee. Secondo il libro MySQL ad alte prestazioni. Quando l'ottimizzatore tenta di vedere se è in grado di eseguire questa query in memoria o se necessita di una tabella temporanea, esamina la dimensione della riga in base alla definizione della tabella, ovvero, per velocità, non prova a vedere la quantità di 64 KB di caratteri stai effettivamente usando. Questo è il motivo per cui gli autori raccomandano di non estendere quella definizione ben oltre i possibili valori effettivi che andrebbero nella colonna. Ovviamente, se ti imposti per ulteriori query andando nelle tabelle temporanee (anche se la dimensione effettiva dei dati potrebbe rientrare nella RAM) ora hai subito penalità I / O che avresti potuto evitare.


Questa è una prospettiva molto nuova. Se questo è il libro a cui ti riferisci ( amazon.com/MySQL-High-Availability-Building-Centers/dp/… ), inserisci il numero di pagina del libro nella tua risposta, perché vorrei leggerlo. +1 !!!
RolandoMySQLDBA,

Silly me ... High PERFORMANCE non disponibilità: amazon.com/High-Performance-MySQL-Optimization-Replication/dp/…… il numero di pagina è 236/237 Spiega come la generosità nella definizione di una colonna varchar può essere poco saggia. Tieni presente, tuttavia, che questo libro è stato riscritto quando 5.1 era appena uscito. Il prossimo anno uscirà una terza edizione per includere tutti i GRANDI cambiamenti nella 5.5, quindi forse cambierà :)
TechieGurl,

Pagina 236 menziona le regole di confronto appartenenti a particolari set di caratteri. Potrebbe essere un po 'brutto per VARCHAR. A pagina 237, le impostazioni per le comunicazioni client / server insieme alla Figura 5-5 a pagina 238 mostrano un altro motivo. Il processo di traduzione dei caratteri va avanti e indietro. Ancora una volta, un'altra brutta avventura per VARCHAR.
RolandoMySQLDBA,

Per chiarire, anche se questa sezione non dice apertamente che MySQL cercherà di creare dimensioni, sappiamo che quando un'operazione ha bisogno di una tabella temporanea quella tabella è in MEMORY Engine e CHE memorizza sempre i tipi di stringa in blocchi di correzioni in modo che sia il generoso la definizione può far sì che la tabella delle temperature MEMORY necessaria vada sul disco invece di rimanere nella RAM
TechieGurl,

@RolandoMySQLDBA. Sì ... anche quello ... anche la collazione diventa un fattore qui (specialmente se usi UTF-8 e hai caratteri non latini) e tutto ti uccide quando hai a che fare con una tabella del motore di memoria e porta a un viaggio più veloce su disco
TechieGurl

5

Comprendo che i campi più piccoli possono essere inclusi direttamente nell'indice, mentre quelli più lunghi non possono essere inclusi. A causa di tale limitazione, se si desidera che le stringhe siano indicizzabili, direi di mantenerle più brevi. Altrimenti, no, essendo come sono entrambi varchar, le operazioni come l'ordinamento o il confronto funzioneranno in modo simile, indipendentemente dal fatto che i campi siano 25 o MAX.


3

assicurarsi di non rimanere a corto di spazio

Questa frase implica che si pone la domanda perché non si è sicuri dei dati che verranno archiviati nel database. Se questo è vero, sarai ben servito a scoprirlo il prima possibile, perché ne avrai bisogno per la pianificazione della capacità. Ad esempio, se si ottengono elementi di dati con 7000 caratteri, è necessario sapere perché ciò avrebbe implicazioni in termini di prestazioni su qualsiasi DBMS.

Detto questo, preferisco avere dimensioni delle colonne correlate ai contenuti previsti. Ad esempio, è improbabile che un numero di telefono sia più lungo di 50 caratteri, anche se includi un prefisso internazionale e un interno. Allo stesso modo, un codice postale o postale sarà probabilmente di 20 caratteri o meno.

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.