Esistono degli svantaggi nell'usare un varchar generico (255) per tutti i campi di testo?


100

Ho un contactstavolo che contiene i campi, come postcode, first name, last name, town, country, phone numberecc, che sono tutti definiti come VARCHAR(255)anche se nessuno di questi campi verrà mai vicino ad avere 255 caratteri. (Se ti stai chiedendo, è in questo modo perché le migrazioni di Ruby on Rails mappano i campi String per VARCHAR(255)impostazione predefinita e non mi sono mai preoccupato di sovrascriverlo).

Poiché VARCHAR memorizzerà solo il numero di caratteri effettivi del campo (insieme alla lunghezza del campo), c'è qualche vantaggio distinto (prestazioni o altro) nell'usare, ad esempio, VARCHAR(16)oltre VARCHAR(255)?

Inoltre, la maggior parte di questi campi dispone di indici. Una dimensione VARCHAR maggiore sul campo influisce sulle dimensioni o sulle prestazioni dell'indice?

Cordiali saluti, sto usando MySQL 5.


2
@ceejayoz, affermando che la risposta accettata non è corretta senza spiegare perché non aiuta davvero. Ciò che lo rende ancora peggiore è che la risposta accettata può cambiare nel tempo e il tuo commento confonderà le persone facendole pensare che la nuova risposta accettata non sia corretta.
Gili

1
@Gili Ho cancellato il mio commento poiché l'OP apparentemente ha cambiato la loro accettazione. Aspetti positivi, in futuro indicherò di quale risposta sto parlando e perché.
ceejayoz

Alcune altre risposte a questa domanda duplicata, stackoverflow.com/questions/1262174/…
James McMahon

Risposte:


129

Nell'archiviazione, VARCHAR(255)è abbastanza intelligente da memorizzare solo la lunghezza necessaria su una determinata riga, a differenza della CHAR(255)quale memorizzerebbe sempre 255 caratteri.

Ma poiché hai etichettato questa domanda con MySQL, menzionerò un suggerimento specifico di MySQL: quando le righe vengono copiate dal livello del motore di archiviazione al livello SQL, i VARCHARcampi vengono convertiti in CHARper ottenere il vantaggio di lavorare con righe a larghezza fissa. Quindi le stringhe in memoria vengono riempite fino alla lunghezza massima della VARCHARcolonna dichiarata .

Quando la tua query genera implicitamente una tabella temporanea, ad esempio durante l'ordinamento o GROUP BY, questo può utilizzare molta memoria. Se si utilizzano molti VARCHAR(255)campi per dati che non devono essere così lunghi, la tabella temporanea può essere molto grande.

Potresti anche sapere che questo comportamento di "riempimento" significa che una stringa dichiarata con il set di caratteri utf8 si estende fino a tre byte per carattere anche per le stringhe memorizzate con contenuto a byte singolo (ad es. Caratteri ascii o latin1). Allo stesso modo, il set di caratteri utf8mb4 fa sì che la stringa si riempia fino a quattro byte per carattere in memoria.

Quindi un VARCHAR(255)in utf8 che memorizza una breve stringa come "Nessuna opinione" richiede 11 byte su disco (dieci caratteri con set di caratteri inferiori, più un byte per la lunghezza) ma richiede 765 byte in memoria, e quindi in tabelle temporanee o risultati ordinati.

Ho aiutato gli utenti MySQL che creavano inconsapevolmente tabelle temporanee da 1,5 GB frequentemente e riempivano il loro spazio su disco. Avevano molte VARCHAR(255)colonne che in pratica memorizzavano stringhe molto brevi.

È meglio definire la colonna in base al tipo di dati che si intende archiviare. Ha dei vantaggi nel far rispettare i vincoli relativi alle applicazioni, come hanno già detto altre persone. Ma ha i benefici fisici per evitare lo spreco di memoria che ho descritto sopra.

È difficile sapere quale sia l'indirizzo postale più lungo, ovviamente, motivo per cui molte persone scelgono un lungo VARCHARche è sicuramente più lungo di qualsiasi indirizzo. E 255 è consuetudine perché è la lunghezza massima di a VARCHARper la quale la lunghezza può essere codificata con un byte. Era anche la VARCHARlunghezza massima in MySQL precedente alla 5.0.


6
Ho sempre pensato che 255fosse usato in modo che la lunghezza della stringa potesse rientrare in un singolo byte
BlueRaja - Danny Pflughoeft

3
@BlueRaja: Probabilmente era vero per i database la cui struttura di file interna codificava la lunghezza di una stringa in un singolo byte o se codificavano stringhe brevi in ​​un singolo byte. Ma non è più vero per la maggior parte dei database.
Bill Karwin

7
@BlueRaja: InnoDB non memorizza la lunghezza del seguente varchar, memorizza una serie di offset di campo per tutti i campi nella riga. Questi offset di campo possono essere 1 byte se la dimensione totale della riga è inferiore a 127 byte, oppure 2 byte. Vedi forge.mysql.com/wiki/MySQL_Internals_InnoDB
Bill Karwin

6
@BlueRaja: MyISAM (per coloro che lo usano ancora) memorizza le lunghezze varchar e queste possono essere memorizzate in 1 o 2 byte. Tuttavia: "Quando si invia una chiave al gestore per index_read () o records_in_range, usiamo sempre una lunghezza di 2 byte per il VARCHAR per rendere le cose più semplici." Vedi forge.mysql.com/wiki/MySQL_Internals_MyISAM
Bill Karwin

1
una domanda: ordinamento e raggruppamento in base a qualsiasi campo o al campo varchar stesso?
Rohit Banga

24

Oltre alle considerazioni sulle dimensioni e sulle prestazioni dell'impostazione della dimensione di un varchar (e forse più importante, poiché l'archiviazione e l'elaborazione diventano più economiche ogni secondo), lo svantaggio dell'utilizzo di varchar (255) "solo perché" è l'integrità dei dati ridotta .

La definizione dei limiti massimi per le stringhe è una buona cosa da fare per evitare che stringhe più lunghe del previsto entrino nell'RDBMS e causino sovraccarichi del buffer o eccezioni / errori in un secondo momento durante il recupero e l'analisi dei valori dal database che sono più lunghi (più byte) del previsto.

Ad esempio, se hai un campo che accetta stringhe di due caratteri per le abbreviazioni dei paesi, non hai motivo concepibile per aspettarti che i tuoi utenti (in questo contesto, i programmatori) inseriscano i nomi dei paesi completi. Dato che non vuoi che entrino in "Antigua e Barbuda" (AG) o "Isole Heard e McDonald" (HM), non lo permetti a livello di database. Inoltre, è probabile che alcuni programmatori non abbiano ancora RTFMed la documentazione di progettazione ( che sicuramente esiste ) per sapere di non farlo.

Imposta il campo in modo che accetti due caratteri e lascia che l'RDBMS se ne occupi (con grazia troncando o sgraziatamente rifiutando il loro SQL con un errore).

Esempi di dati reali che non hanno motivo di superare una certa lunghezza:

  • I codici postali canadesi sono nel formato A1A1A1 e sono sempre lunghi 6 caratteri, anche per Babbo Natale (6 caratteri esclude lo spazio che può essere specificato per la leggibilità).
  • indirizzi email : fino a 64 byte prima della @, fino a 255 byte dopo. Mai più, per timore di rompere Internet.
  • I numeri di telefono del Nord America non sono mai più di 10 cifre (escluso il prefisso internazionale).
  • I computer che eseguono (versioni recenti di) Windows non possono avere nomi di computer più lunghi di 63 byte , sebbene più di 15 non siano consigliati e interromperanno la server farm di Windows NT.
  • Le abbreviazioni di stato sono di 2 caratteri (come i codici paese esemplificati sopra)
  • I numeri di ricerca UPS sono lunghi 18, 12, 11 o 9 caratteri. I numeri di 18 caratteri iniziano con "1Z" e i numeri di 11 caratteri iniziano con "T", il che ti fa chiedere come consegnano tutti quei pacchi se non conoscono la differenza tra lettere e numeri.

E così via...

Prenditi il ​​tempo per pensare ai tuoi dati e ai loro limiti. Se sei un architetto, sviluppatore o programmatore, è il tuo lavoro , dopotutto.

Utilizzando un varchar (n) invece di varchar (255) si elimina il problema in cui gli utenti (utenti finali, programmatori, altri programmi) inseriscono dati inaspettatamente lunghi che torneranno a infestare il codice in seguito.

E non ho detto che non dovresti implementare questa restrizione anche nel codice della logica di business utilizzato dalla tua applicazione.


5
I codici postali canadesi in realtà hanno 7 cifre, lo spazio al centro è importante e dovrebbe essere mostrato sulle etichette postali. I numeri di telefono nordamericani possono contenere più di 10 cifre se è presente un'estensione. Se sei OK non essere in grado di memorizzare gli interni del numero di telefono, allora 10 cifre vanno bene, ma probabilmente te ne pentirai.
Kibbee,

3
C'è sicuramente un motivo per restringere l'integrità dei dati. Tuttavia, è ancora facile essere troppo restrittivi. Imponi restrizioni per i dati che controlli e imponi restrizioni sensate per i requisiti dei dati che non puoi controllare. Il tuo numero di telefono e le restrizioni relative alla posta elettronica sono sensati (supponendo che tu non internazionalizzi mai). Il tuo requisito che dice che troncare un codice paese di due caratteri è la cosa "graziosa" è folle. Sai che c'è stato un errore, non troncare e accettare. Se troncate c'è una probabilità estremamente alta che vi ritroverete con un codice paese errato.
coderjoe

La maggior parte delle applicazioni avrà la convalida dei dati prima di inviarli al database ...
Cobby

2
Sicuro. Maggior parte. Ma sento che qui stai assumendo che uno sviluppatore che sta sviluppando una nuova applicazione per un database esistente sia a conoscenza delle restrizioni sui dati (non siamo tutti esperti su ogni tipo di dati e su come è implementato in ogni database ). Solo perché puoi convalidare i dati nella tua applicazione non significa che l'hai fatto.
shufler

3
the design documentation (which surely exists)Hah. : D
Camilo Martin

14

Sono con te. L'attenzione pignola ai dettagli è un dolore al collo e ha un valore limitato.

Un tempo il disco era un bene prezioso e per ottimizzarlo eravamo soliti sudare proiettili. Il prezzo di archiviazione è diminuito di un fattore 1.000, rendendo meno prezioso il tempo speso per comprimere ogni byte.

Se utilizzi solo campi CHAR, puoi ottenere righe di lunghezza fissa. Ciò può far risparmiare una riformulazione reale del disco se hai scelto dimensioni accurate per i campi. Potresti ottenere dati più densi (meno I / O per le scansioni delle tabelle) e aggiornamenti più veloci (più facile individuare gli spazi aperti in un blocco per aggiornamenti e inserimenti).

Tuttavia, se si sovrastima le dimensioni o le dimensioni effettive dei dati sono variabili, si finisce per sprecare spazio con i campi CHAR. I dati finiranno in un pacchetto meno denso (portando a più I / O per i grandi recuperi).

In genere, i vantaggi in termini di prestazioni derivanti dal tentativo di impostare una dimensione sui campi variabili sono minori. Puoi facilmente eseguire il benchmark utilizzando VARCHAR (255) rispetto a CHAR (x) per vedere se puoi misurare la differenza.

Tuttavia, a volte, è necessario fornire un suggerimento "piccolo", "medio", "grande". Quindi uso 16, 64 e 255 per le dimensioni.


13

Al giorno d'oggi, non riesco a immaginare che sia davvero importante.

C'è un sovraccarico di calcolo nell'utilizzo di campi di lunghezza variabile, ma con gli eccessi delle CPU oggi, non vale nemmeno la pena considerarlo. I sistemi di I / O sono così lenti da rendere inesistenti eventuali costi di calcolo per gestire i varchar. In effetti, il prezzo di un varchar computazionalmente è probabilmente una vittoria netta sulla quantità di spazio su disco risparmiato utilizzando campi di lunghezza variabile su campi di lunghezza fissa. Molto probabilmente hai una maggiore densità di righe.

Ora, la complessità dei campi varchar è che non è possibile individuare facilmente un record tramite il suo numero di record. Quando si dispone di una dimensione di riga di lunghezza fissa (con campi di lunghezza fissa), è banale calcolare il blocco del disco a cui punta un ID di riga. Con una dimensione della riga di lunghezza variabile, quel tipo di file esce dalla finestra.

Quindi, ora è necessario mantenere una sorta di indice del numero di record, proprio come qualsiasi altra chiave primaria, OPPURE è necessario creare un robusto identificatore di riga che codifichi i dettagli (come il blocco, ecc.) Nell'identificatore. Se lo fai, però, l'id dovrebbe essere ricalcolato se mai la riga viene spostata su una memoria persistente. Non è un grosso problema, devi solo riscrivere tutte le voci dell'indice e assicurarti di a) non esporlo mai al consumatore oppure b) non affermare mai che il numero è affidabile.

Ma poiché oggi abbiamo campi varchar, l'unico valore di varchar (16) su varchar (255) è che il DB imporrà il limite di 16 caratteri sul varchar (16). Se si suppone che il modello DB sia effettivamente rappresentativo del modello di dati fisico, la lunghezza dei campi può essere utile. Se, tuttavia, è semplicemente "archiviazione" anziché un "modello E archiviazione", non ce n'è bisogno.

Quindi devi semplicemente distinguere tra un campo di testo indicizzabile (come varchar) e qualcosa che non lo è (come un campo di testo o CLOB). I campi indicizzabili tendono ad avere un limite alla dimensione per facilitare l'indice, mentre i campi CLOB non lo fanno (entro limiti ragionevoli).


5

Nella mia esperienza, se consenti un tipo di dati di 255 caratteri, qualche utente stupido (o qualche tester esperto) lo riempirà effettivamente.

Quindi si verificano tutti i tipi di problemi, inclusa la quantità di spazio consentita per quei campi nei rapporti e nelle visualizzazioni su schermo dell'applicazione. Per non parlare della possibilità di superare il limite per riga per i dati nel database (se si dispone di più di alcuni di questi 255 campi di caratteri).

È molto più facile scegliere un limite ragionevole all'inizio, quindi applicarlo tramite l'applicazione e il database.


0

È buona norma allocare solo un po 'più di quello che ti serve. I numeri di telefono non sarebbero mai stati così grandi.

Uno dei motivi è che, a meno che non convalidi con voci di grandi dimensioni, senza dubbio qualcuno utilizzerà tutto ciò che è disponibile. Quindi potresti rimanere senza spazio nella tua fila. Non sono sicuro del limite di MySQL ma 8060 è la dimensione massima delle righe in MS SQL.

Un valore predefinito più normale sarebbe 50 imho, per poi aumentare dove necessario lo dimostra.


Grazie. Sono assolutamente d'accordo sul fatto che sia una buona pratica. È l'aspetto della performance su cui vorrei davvero chiarimenti
Olly

0

In un contesto mysql può diventare importante quando si lavora con gli indici su dette colonne varchar, poiché mysql ha un max. limite di 767 byte per riga di indice.

Ciò significa che quando aggiungi un indice su diverse colonne varchar 255 puoi arrivare a questo limite piuttosto rapidamente / ancora più velocemente sulle colonne utf8 o utf8mb4 come indicato nelle risposte sopra

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.