Importanza della lunghezza varchar nella tabella MySQL


112

Ho una tabella MySQL in cui le righe vengono inserite dinamicamente. Poiché non posso essere certo della lunghezza delle stringhe e non voglio che vengano tagliate, le creo varchar (200) che è generalmente molto più grande di quanto mi serve. C'è un grande calo di prestazioni nel dare a un campo varchar una lunghezza maggiore del necessario?


Una tabella con una singola VARCHAR(255) utf8mb4colonna indicizzata con ~ 150.000 righe misurava 11,5 MB. Una tabella con una VARCHAR(48) utf8mb4colonna indicizzata con gli stessi dati (lunghezza massima 46 caratteri) utilizzava 4,5 MB. Non è proprio una grande differenza nelle query, è indicizzato. Ma si somma con l'I / O delle query e cose come i backup del database.
Code4R7

Risposte:


59

No, nel senso che se i valori che stai memorizzando in quella colonna sono sempre (diciamo) inferiori a 50 caratteri, dichiarando la colonna come varchar(50)o varchar(200)ha le stesse prestazioni.


9
Non esattamente il vero. Vedi risposta di Bill Karwin
hejdav

5
Penso che una risposta come dovrebbe essere supportata da documenti, benchmark o qualcosa di simile.
Gokhan Sari

301

C'è un possibile impatto sulle prestazioni: in MySQL, le tabelle e le MEMORYtabelle temporanee memorizzano una VARCHARcolonna come una colonna di lunghezza fissa, riempita alla sua lunghezza massima. Se progetti VARCHARcolonne molto più grandi della dimensione massima di cui hai bisogno, consumerai più memoria del necessario. Ciò influisce sull'efficienza della cache, sulla velocità di ordinamento, ecc.


33
+1. Ho anche sembrato alcuni driver JDBC che allocano spazio sufficiente per la dimensione massima quando si impostano i buffer per recuperare le righe. Inutile dire che questo provoca molta angoscia e digrignare i denti quando qualche clown ha appena fatto varchar (50000) nel caso qualcuno abbia un cognome davvero grande :-)
paxdiablo

21
+1. Questo è un impatto importante e credo che questa sia la vera risposta a questa domanda.
Emre Yazici

6
Questa risposta e la risposta accettata sono entrambe necessarie per comprendere la risposta corretta all'OP.
kd8azz

2
Infatti, quando una MEMORYtabella di questo tipo è considerata troppo grande, viene scritta su disco, causando una significativa riduzione delle prestazioni.
Timo

1
Questa risposta potrebbe fare con la specifica di quali motori di archiviazione è vero (noto che dev.mysql.com/doc/refman/8.0/en/… indica che le tabelle temporanee sono sempre InnoDB a partire da MySQL 8; cambia qualcosa?) e con collegamenti a documenti che supportano le affermazioni che fa. Da quello che ho visto del tuo output su Stack Exchange, ho fede che avevi ragione quando hai scritto questo, ma le cose potrebbero essere cambiate e i collegamenti sarebbero entrambi un buon esempio per gli altri e aiuterebbero a insegnare al resto di noi a trovare questo tipo di informazioni per noi stessi.
Mark Amery

14

VARCHAR è l'ideale per la situazione che descrivi, perché sta per "carattere variabile": il limite, in base al tuo esempio, sarebbe di 200 caratteri, ma qualsiasi cosa inferiore è accettata e non riempirà la dimensione assegnata della colonna.

VARCHAR occupa anche meno spazio: i valori vengono memorizzati come prefisso di lunghezza di un byte o due byte più dati. Il prefisso della lunghezza indica il numero di byte nel valore. Una colonna utilizza un byte di lunghezza se i valori non richiedono più di 255 byte, due byte di lunghezza se i valori possono richiedere più di 255 byte.

Per ulteriori informazioni sul confronto tra i tipi di dati MySQL CHAR e VARCHAR, vedere questo collegamento .


1
chiunque sia interessato all'archiviazione MySQL (su CHAR e VARCHAR) dovrebbe leggere il collegamento menzionato in questa risposta. Grazie!
Pascal

14

Le dimensioni sono prestazioni! Più piccola è la dimensione, meglio è. Non oggi o domani, ma un giorno i tuoi tavoli diventeranno di dimensioni adeguate quando si tratta di gravi colli di bottiglia, indipendentemente dal design che hai preparato. Ma puoi prevedere alcuni di quei potenziali colli di bottiglia nella tua fase di progettazione che probabilmente si verificheranno per primi e cercare di espandere il tempo in cui il tuo db funzionerà velocemente e felicemente finché non avrai bisogno di ripensare il tuo schema o ridimensionare orizzontalmente aggiungendo più server.

Nel tuo caso ci sono molte perdite di prestazioni in cui puoi incorrere: i grandi join sono quasi impossibili con varcharcolonne lunghe . L'indicizzazione su quelle colonne è un vero assassino. Il tuo disco deve memorizzare i dati. Una pagina di memoria può contenere meno righe e le scansioni delle tabelle saranno molto più lente. Inoltre, è improbabile che la cache delle query ti aiuti qui.

Devi chiederti: quanti inserti all'anno possono accadere? Qual è la lunghezza media? Ho davvero bisogno di più di 200 caratteri o posso individuarli nel front-end della mia applicazione, anche informando gli utenti della lunghezza massima? Posso dividere la tabella in una più stretta per l'indicizzazione e la scansione veloci e un'altra per contenere dati aggiuntivi, meno frequentemente necessari, di dimensioni in espansione? Posso digitare i possibili dati varchar in categorie e quindi estrarre alcuni dati in alcune colonne più piccole, magari int o di tipo bool, e restringere la colonna varchar in questo modo?

Puoi fare molto qui. Potrebbe essere meglio partire da un primo presupposto e poi riprogettare passo dopo passo utilizzando dati sulle prestazioni misurate nella vita reale. In bocca al lupo.


+1 per le opzioni di progettazione degli elenchi e per esplorare l'impatto. Molto utile anche per la mia domanda. stackoverflow.com/q/12083089/181638
Assad Ebrahim

5
Esiste un impatto effettivo sulle prestazioni dall'impostazione di una lunghezza massima elevata o le prestazioni sono determinate solo dalle dimensioni effettive?
poolie

5

Prestazione? No. Memoria su disco? Sì, ma è economico e abbondante. A meno che il tuo database non raggiunga la scala dei terabyte, probabilmente stai bene.


Strano che questa risposta sia stata sottovalutata sei anni dopo che è stata pubblicata e nessuna delle altre lo era. Sembra vendicativo e meschino. Non c'è niente di sbagliato in questa risposta. Moderatori?
duffymo

1
Come è stato detto, influisce sulle prestazioni. Inoltre, neanche l'archiviazione su disco è gratuita. Una colonna più ampia significa più letture / scritture su disco (e l'accesso al disco è slooooooow) e anche indici più ampi, il che riduce la loro utilità. Entrambe le cose hanno un impatto negativo sulle prestazioni. Forse è trascurabile su un piccolo database, ma su scala gigabyte / terabyte sarà sicuramente importante, come dici tu. Per una tabella di 100 registri, non importa.
Alejandro

5

Alcuni di voi si sbagliano pensando che a varchar(200)occupi più dimensioni della tabella su disco rispetto a un file varchar(20). Questo non è il caso. Solo quando vai oltre 255 caratteri mysql usa un byte extra per determinare la lunghezza dei varchardati del campo.


9
Non così per tabelle e MEMORYtabelle temporanee .
Gare di leggerezza in orbita

4
Ogni volta che la query di selezione utilizza una tabella temporanea (raggruppa e ordina per operazioni, tra le altre cose) convertirà varchar (200) in un carattere (200) e le prestazioni ne risentiranno.
Jamie

1

Possono esserci successi nelle prestazioni, ma di solito non a un livello che la maggior parte degli utenti noterebbe.

Quando la dimensione di ogni campo è nota in anticipo, MySQL sa esattamente quanti byte ci sono tra ogni campo / riga e può andare avanti senza leggere tutti i dati. L'uso di caratteri variabili riduce questa capacità di ottimizzazione.

Varchar comporta un calo delle prestazioni a causa della frammentazione dei dati?

Ancora meglio, char vs varchar .

Per la maggior parte degli usi, andrà tutto bene con entrambi - ma non v'è una differenza, e per i database di grandi dimensioni, ci sono ragioni per le quali ci si scegliere l'uno o l'altro.


0

Essendo varchar, anziché solo char, la dimensione si basa su un campo interno per indicare la sua lunghezza effettiva e la stringa stessa. Quindi usare varchar (200) non è molto diverso dall'usare varchar (150), tranne per il fatto che hai il potenziale per archiviarne di più.

E dovresti considerare cosa succede con un aggiornamento, quando una riga cresce. Ma se questo è raro, allora dovresti stare bene.


0

secondo il nome del tipo di dati suggerisce che questo è VARCHAR, ovvero l'archiviazione dei dati con caratteri variabili, il motore mysql stesso alloca la memoria utilizzata in base ai dati memorizzati, quindi non vi è alcun calo delle prestazioni secondo la mia conoscenza.


0

Dovresti provare a visualizzare una colonna varchar come faresti con una colonna char nella maggior parte degli scenari e impostare la lunghezza in modo conservativo. Non devi sempre pensare al modificatore var come a qualcosa che influisce sul tuo processo decisionale sulla lunghezza massima. In realtà dovrebbe essere visto come un suggerimento per le prestazioni invece che le corde fornite saranno di lunghezza variabile.

Non è una direttiva che deve essere rigorosamente seguita dagli interni del database, può essere completamente ignorata. Fai attenzione a questo, tuttavia, poiché a volte l'implementazione può perdere (lunghezza fissa e imbottitura per esempio) anche se non dovrebbe in un mondo ideale.

Se hai un varchar (255), non hai alcuna garanzia che le prestazioni si comporteranno sempre in modo diverso da un char (255) in tutte le circostanze.

Può sembrare facile impostarlo su qualcosa come 255, 65535, ecc. In linea con i consigli forniti nel manuale sui requisiti di archiviazione. Questo dà l'impressione che qualsiasi valore compreso tra 0 (sì, è una cosa) e 255 avrà lo stesso impatto. Tuttavia non è qualcosa che può essere completamente garantito.

I requisiti di archiviazione tendono ad essere veri o un buon indicatore per motori di archiviazione persistenti decenti e maturi in termini di archiviazione delle righe. Non è un indicatore così forte per cose come gli indici.

A volte è una domanda difficile, esattamente quanto dovrebbe essere lungo un pezzo di corda in modo da impostarlo fino al limite più alto che sai dovrebbe essere all'interno ma ciò non ha alcun impatto. Sfortunatamente questo è spesso qualcosa lasciato all'utente da risolvere ed è davvero un po 'arbitrario. Non puoi davvero dire mai sovradimensionare una stringa perché forse ci sono casi in cui non sei esattamente sicuro.

Dovresti assicurarti che le query MySQL generino un errore quando una stringa è troppo lunga piuttosto che troncare in modo che almeno tu sappia se potrebbe essere troppo breve per l'emissione di errori. Il ridimensionamento delle colonne per ingrandirle o rimpicciolirle può essere un'operazione DDL costosa, questo dovrebbe essere tenuto presente.

Il set di caratteri dovrebbe essere considerato anche dove entrano in gioco la lunghezza e le prestazioni. La lunghezza si riferisce a questo invece che ai byte. Se si utilizza utf8 ad esempio, (non MB4), varchar (255) è in realtà varbinary (3 * 255). È difficile sapere come andranno davvero a finire cose come questa senza eseguire test e analizzare a fondo il codice sorgente / la documentazione. Per questo motivo, è possibile che una lunghezza eccessiva abbia un impatto inaspettatamente gonfiato. questo non si applica solo alle prestazioni. Se un giorno hai bisogno di cambiare il set di caratteri di una colonna varchar in uno più grande, potresti finire per raggiungere un limite senza possibilità di ricorso se hai consentito la presenza di stringhe gratuitamente lunghe che avrebbero potuto essere evitate. Questo è normalmente un problema abbastanza di nicchia ma si presenta,

Se risulta che MAX (LENGTH (colonna)) è sempre <64 (come se fosse stato deciso che ci sarebbe stato un limite all'input che non corrispondeva alla definizione della colonna) ma hai varchar (255) allora c'è un buone possibilità che utilizzerai quattro volte più spazio del necessario in alcuni scenari.

Ciò potrebbe includere:

  • Motori diversi, alcuni potrebbero ignorarlo del tutto.
  • Le dimensioni del buffer, ad esempio l'aggiornamento o l'inserimento, potrebbero dover allocare l'intero 255 (sebbene non abbia controllato il codice sorgente per dimostrarlo, è solo ipotetico).
  • Indici, questo sarà immediatamente ovvio se provi a creare una chiave composta da molte colonne varchar (255).
  • Tabelle intermedie ed eventualmente set di risultati. Dato il modo in cui funzionano le transazioni, potrebbe non essere sempre possibile che qualcosa utilizzi la lunghezza massima effettiva delle stringhe in una colonna anziché il limite definito.
  • Le ottimizzazioni predittive interne potrebbero prendere la lunghezza massima come input.
  • Modifiche nelle versioni dell'implementazione del database.

Come regola generale, non c'è davvero bisogno che un varchar sia più lungo di quanto deve essere comunque, problemi di prestazioni o meno, quindi ti consiglio di attenersi a quello quando puoi. Fare uno sforzo maggiore per campionare la dimensione dei dati, imporre un limite reale o scoprire il vero limite attraverso domande / ricerche è l'approccio ideale.

Quando non puoi, se vuoi fare qualcosa come varchar (255) per i casi in cui sei in dubbio, ti consiglio di fare scienza. Ciò potrebbe consistere nel duplicare la tabella, ridurre la dimensione della colonna var char quindi copiare i dati in essa dall'originale e osservare la dimensione dei dati di indice / riga (indicizzare anche la colonna, provalo anche come chiave primaria che potrebbe comportarsi diversamente in InnoDB poiché le righe sono ordinate in base alla chiave primaria). Almeno in questo modo saprai se hai un impatto sull'IO che tende ad essere uno dei colli di bottiglia più sensibili. Testare l'utilizzo della memoria è più difficile, è difficile testarlo in modo esaustivo. Consiglierei di testare i potenziali casi peggiori (query con molti risultati intermedi in memoria, controllare con la spiegazione per tabelle temporanee di grandi dimensioni, ecc.).

Se sai che non ci saranno molte righe nella tabella, non utilizzerai la colonna per i join, gli indici (specialmente composti, univoci), ecc., Allora molto probabilmente non avrai molti problemi.

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.