Gibt es Nachteile bei der Verwendung eines generischen Varchars (255) für alle textbasierten Felder?

100

Ich habe eine contactsTabelle , die Felder wie enthält postcode, first name, last name, town, country, phone numberusw., von denen alle definiert werden als VARCHAR(255)auch wenn keines dieser Felder wird jemals nahe kommen 255 Zeichen haben. (Wenn Sie sich fragen, ist dies so, weil Ruby on Rails-Migrationen VARCHAR(255)standardmäßig Zeichenfolgenfelder zuordnen und ich mich nie darum gekümmert habe, sie zu überschreiben.)

Da VARCHAR nur die Anzahl der tatsächlichen Zeichen des Feldes (zusammen mit der Feldlänge) speichert, gibt es einen deutlichen Vorteil (Leistung oder auf andere Weise) bei der Verwendung von beispielsweise VARCHAR(16)gegenüber VARCHAR(255)?

Darüber hinaus sind die meisten dieser Felder mit Indizes versehen. Beeinflusst eine größere VARCHAR-Größe im Feld die Größe oder Leistung des Index überhaupt?

Zu Ihrer Information Ich verwende MySQL 5.

Olly
quelle
2
@ceejayoz, der besagt, dass die akzeptierte Antwort falsch ist, ohne zu erklären, warum das nicht wirklich hilft. Was es noch schlimmer macht, ist, dass sich die akzeptierte Antwort im Laufe der Zeit ändern kann und Ihr Kommentar die Leute verwirren wird, zu denken, dass die neue akzeptierte Antwort falsch ist.
Gili
1
@Gili Löschte meinen Kommentar, da das OP anscheinend ihre Akzeptanz geändert hat. Gute Punkte, in Zukunft werde ich angeben, über welche Antwort ich spreche und warum.
Ceejayoz
Einige andere Antworten auf diese doppelte Frage, stackoverflow.com/questions/1262174/…
James McMahon

Antworten:

129

Im Speicher VARCHAR(255)ist es intelligent genug, nur die Länge zu speichern, die Sie in einer bestimmten Zeile benötigen, im Gegensatz dazu, in CHAR(255)der immer 255 Zeichen gespeichert würden.

Da Sie diese Frage jedoch mit MySQL markiert haben, erwähne ich einen MySQL-spezifischen Tipp: Wenn Zeilen von der Storage Engine-Schicht in die SQL-Schicht kopiert werden, werden VARCHARFelder in konvertiert CHAR, um den Vorteil der Arbeit mit Zeilen mit fester Breite zu erzielen. So werden die Zeichenfolgen im Speicher auf die maximale Länge Ihrer deklarierten VARCHARSpalte aufgefüllt .

Wenn Ihre Abfrage implizit eine temporäre Tabelle generiert, beispielsweise beim Sortieren oder GROUP BY, kann dies viel Speicherplatz beanspruchen. Wenn Sie viele VARCHAR(255)Felder für Daten verwenden, die nicht so lang sein müssen, kann dies die temporäre Tabelle sehr groß machen.

Vielleicht möchten Sie auch wissen, dass dieses "Auffüllen" -Verhalten bedeutet, dass eine mit dem utf8-Zeichensatz deklarierte Zeichenfolge auf drei Bytes pro Zeichen aufgefüllt wird, selbst für Zeichenfolgen, die Sie mit Einzelbyte-Inhalten speichern (z. B. ASCII- oder Latin1-Zeichen). Ebenso bewirkt der Zeichensatz utf8mb4, dass die Zeichenfolge auf vier Bytes pro Zeichen im Speicher aufgefüllt wird.

Ein VARCHAR(255)in utf8, das eine kurze Zeichenfolge wie "Keine Meinung" speichert, benötigt also 11 Bytes auf der Festplatte (zehn Zeichen mit niedrigerem Zeichensatz plus ein Byte für die Länge), aber 765 Bytes im Speicher und damit in temporären Tabellen oder sortierten Ergebnissen.

Ich habe MySQL-Benutzern geholfen, die unwissentlich häufig 1,5-GB-temporäre Tabellen erstellt und ihren Speicherplatz gefüllt haben. Sie hatten viele VARCHAR(255)Spalten, in denen in der Praxis sehr kurze Zeichenfolgen gespeichert waren.

Definieren Sie die Spalte am besten basierend auf dem Datentyp, den Sie speichern möchten. Es hat Vorteile, anwendungsbezogene Einschränkungen durchzusetzen, wie andere Leute erwähnt haben. Aber es hat die physischen Vorteile, die oben beschriebene Speicherverschwendung zu vermeiden.

Es ist natürlich schwer zu wissen, wie die längste Postanschrift lautet, weshalb viele Leute eine lange wählen VARCHAR, die sicherlich länger ist als jede andere Adresse. Und 255 ist üblich, weil es die maximale Länge von a ist, VARCHARfür die die Länge mit einem Byte codiert werden kann. Es war auch die maximale VARCHARLänge in MySQL älter als 5.0.

Bill Karwin
quelle
6
Ich dachte immer, es 255wurde verwendet, damit die Länge der Zeichenfolge in ein einzelnes Byte passt
BlueRaja - Danny Pflughoeft
3
@BlueRaja: Das galt wahrscheinlich für Datenbanken, deren interne Dateistruktur die Länge einer Zeichenfolge in einem einzelnen Byte codierte, oder wenn sie kurze Zeichenfolgen in einem einzelnen Byte codierten. Für die meisten Datenbanken gilt dies jedoch nicht mehr.
Bill Karwin
7
@BlueRaja: InnoDB speichert nicht die Länge des folgenden Varchars, sondern eine Reihe von Feldversätzen für alle Felder in der Zeile. Diese Feldversätze können 1 Byte betragen, wenn die Gesamtzeilengröße weniger als 127 Byte beträgt, oder 2 Byte. Siehe forge.mysql.com/wiki/MySQL_Internals_InnoDB
Bill Karwin
6
@BlueRaja: MyISAM (für diejenigen, die es noch verwenden) speichert Varchar-Längen, und diese können in 1 oder 2 Bytes gespeichert werden. Allerdings: "Wenn Sie einen Schlüssel für index_read () oder records_in_range an den Handler senden, verwenden wir immer eine Länge von 2 Byte für VARCHAR, um die Arbeit zu vereinfachen." Siehe forge.mysql.com/wiki/MySQL_Internals_MyISAM
Bill Karwin
1
eine Frage - Sortieren und Gruppieren nach einem beliebigen Feld oder dem Varchar-Feld selbst?
Rohit Banga
24

Zusätzlich zu den Größen- und Leistungsaspekten beim Festlegen der Größe eines Varchars (und möglicherweise wichtiger, da Speicher und Verarbeitung mit jeder Sekunde billiger werden) besteht der Nachteil der Verwendung von Varchar (255) "nur weil" in der verringerten Datenintegrität .

Das Definieren von Höchstgrenzen für Zeichenfolgen ist eine gute Methode, um zu verhindern, dass länger als erwartete Zeichenfolgen in das RDBMS gelangen und später Pufferüberläufe oder Ausnahmen / Fehler verursachen, wenn Werte aus der Datenbank abgerufen und analysiert werden, die länger (mehr Bytes) als erwartet sind.

Wenn Sie beispielsweise ein Feld haben, das zweistellige Zeichenfolgen für Länderabkürzungen akzeptiert, haben Sie keinen denkbaren Grund zu erwarten, dass Ihre Benutzer (in diesem Zusammenhang Programmierer) vollständige Ländernamen eingeben. Da Sie nicht möchten, dass sie "Antigua und Barbuda" (AG) oder "Heard Island und McDonald Islands" (HM) eingeben, lassen Sie dies auf Datenbankebene nicht zu. Es ist auch wahrscheinlich, dass einige Programmierer die Konstruktionsdokumentation ( die sicherlich vorhanden ist ) noch nicht RTFMed haben, um zu wissen, dass sie dies nicht tun sollen.

Stellen Sie das Feld so ein, dass zwei Zeichen akzeptiert werden, und lassen Sie das RDBMS damit umgehen (entweder ordnungsgemäß durch Abschneiden oder unanständig durch Zurückweisen des SQL mit einem Fehler).

Beispiele für reale Daten, die keinen Grund haben, eine bestimmte Länge zu überschreiten:

  • Kanadische Postleitzahlen haben das Format A1A1A1 und sind auch für den Weihnachtsmann immer 6 Zeichen lang (6 Zeichen schließen den Platz aus, der für die Lesbarkeit angegeben werden kann).
  • E-Mail-Adressen - bis zu 64 Byte vor dem @, bis zu 255 Byte danach. Nie mehr, damit Sie nicht das Internet brechen.
  • Nordamerikanische Telefonnummern sind nie mehr als 10 Ziffern (ohne die Landesvorwahl).
  • Computer, auf denen (neuere) Versionen von Windows ausgeführt werden, dürfen keine Computernamen haben, die länger als 63 Byte sind. Mehr als 15 werden jedoch nicht empfohlen und beschädigen Ihre Windows NT-Serverfarm.
  • Die staatlichen Abkürzungen bestehen aus 2 Zeichen (wie die oben aufgeführten Ländercodes).
  • UPS Tracking-Nummern sind entweder 18-, 12-, 11- oder 9-stellig. Die 18-stelligen Zahlen beginnen mit "1Z" und die 11-stelligen Zahlen beginnen mit "T". Sie fragen sich, wie sie all diese Pakete liefern, wenn sie den Unterschied zwischen Buchstaben und Zahlen nicht kennen.

Und so weiter...

Nehmen Sie sich Zeit, um über Ihre Daten und ihre Grenzen nachzudenken. Wenn Sie Architekt, Entwickler oder Programmierer sind, ist es schließlich Ihre Aufgabe .

Durch die Verwendung beseitigen Sie eine varchar (n) anstelle von varchar (255) , um das Problem in dem Benutzer (Endbenutzer, Programmierer, andere Programme) eingeben unerwartet lange Daten , die werden zurückkommen Code später zu verfolgen.

Und ich habe nicht gesagt, dass Sie diese Einschränkung nicht auch in den von Ihrer Anwendung verwendeten Geschäftslogikcode implementieren sollten.

schlurfen
quelle
5
Kanadische Postleitzahlen haben tatsächlich 7 Ziffern, der Platz in der Mitte ist wichtig und sollte auf Versandetiketten angegeben werden. Nordamerikanische Telefonnummern können bei einer Verlängerung mehr als 10 Ziffern haben. Wenn Sie in der Lage sind, Telefonnummernerweiterungen nicht zu speichern, sind 10 Ziffern in Ordnung, aber Sie werden es wahrscheinlich bereuen.
Kibbee
3
Es gibt definitiv einen Grund, die Datenintegrität einzuschränken. Es ist jedoch immer noch leicht, zu restriktiv zu sein. Legen Sie Einschränkungen für Daten fest, die Sie kontrollieren, und legen Sie vernünftige Einschränkungen für Datenanforderungen fest, die Sie nicht kontrollieren können. Ihre Telefonnummer und E-Mail-Einschränkungen sind vernünftig (vorausgesetzt, Sie internationalisieren nie). Ihre Anforderung, dass das Abschneiden eines zweistelligen Ländercodes "anmutig" ist, ist verrückt. Sie wissen, dass ein Fehler aufgetreten ist. Schneiden Sie ihn nicht ab und akzeptieren Sie ihn. Wenn Sie abschneiden, besteht eine extrem hohe Wahrscheinlichkeit, dass Sie einen falschen Ländercode erhalten.
Coderjoe
Bei den meisten Anwendungen wird die Daten überprüft, bevor sie an die Datenbank
gesendet
2
Sicher. Die meisten. Ich gehe jedoch davon aus, dass Sie davon ausgehen, dass ein Entwickler, der eine neue Anwendung für eine vorhandene Datenbank entwickelt, die Einschränkungen der Daten kennt (wir sind nicht alle Experten für jeden Datentyp und dessen Implementierung in jeder Datenbank ). Nur weil Sie Daten in Ihrer Anwendung validieren können, heißt das nicht, dass Sie dies getan haben.
Shufler
3
the design documentation (which surely exists)Hah. : D
Camilo Martin
14

Ich bin bei dir. Sorgfältige Liebe zum Detail ist ein Schmerz im Nacken und hat einen begrenzten Wert.

Es war einmal eine kostbare Ware, und wir schwitzten Kugeln, um sie zu optimieren. Der Speicherpreis ist um den Faktor 1.000 gesunken, wodurch die Zeit, die für das Zusammendrücken jedes Bytes aufgewendet wird, weniger wertvoll ist.

Wenn Sie nur CHAR-Felder verwenden, können Sie Zeilen mit fester Länge erhalten. Dies kann einige echte Änderungen an der Festplatte einsparen, wenn Sie genaue Größen für Felder ausgewählt haben. Möglicherweise erhalten Sie dichter gepackte Daten (weniger E / A für Tabellenscans) und schnellere Aktualisierungen (einfachere Suche nach offenen Stellen in einem Block für Aktualisierungen und Einfügungen).

Wenn Sie jedoch Ihre Größen überschätzen oder Ihre tatsächlichen Datengrößen variabel sind, verschwenden Sie Platz mit CHAR-Feldern. Die Daten werden weniger dicht gepackt (was zu mehr E / A für große Abfragen führt).

Im Allgemeinen sind die Leistungsvorteile beim Versuch, eine Größe für variable Felder festzulegen, gering. Mit VARCHAR (255) im Vergleich zu CHAR (x) können Sie problemlos einen Benchmark durchführen, um festzustellen, ob Sie den Unterschied messen können.

Manchmal muss ich jedoch einen "kleinen", "mittleren", "großen" Hinweis geben. Also benutze ich 16, 64 und 255 für die Größen.

S.Lott
quelle
13

Heutzutage kann ich mir nicht mehr vorstellen, dass es wirklich wichtig ist.

Die Verwendung von Feldern mit variabler Länge ist mit einem Rechenaufwand verbunden, aber angesichts der heutigen Überschüsse an CPUs lohnt es sich nicht einmal, darüber nachzudenken. Das E / A-System ist so langsam, dass keine Rechenkosten für die effektive Handhabung von Varchars anfallen. Tatsächlich ist der Preis eines Varchars rechnerisch wahrscheinlich ein Nettogewinn gegenüber der Menge an Speicherplatz, die durch die Verwendung von Feldern variabler Länge gegenüber Feldern fester Länge eingespart wird. Sie haben höchstwahrscheinlich eine größere Zeilendichte.

Die Komplexität von Varchar-Feldern besteht nun darin, dass Sie einen Datensatz nicht einfach über seine Datensatznummer finden können. Wenn Sie eine Zeilengröße fester Länge (mit Feldern fester Länge) haben, ist es trivial, den Plattenblock zu berechnen, auf den eine Zeilen-ID zeigt. Bei einer Zeilengröße variabler Länge geht diese Art aus dem Fenster.

Jetzt müssen Sie wie bei jedem anderen Primärschlüssel eine Art Datensatznummernindex verwalten ODER eine robuste Zeilenkennung erstellen, die Details (wie den Block usw.) in die Kennung codiert. In diesem Fall müsste die ID jedoch neu berechnet werden, wenn die Zeile jemals in einen dauerhaften Speicher verschoben wird. Keine große Sache, Sie müssen nur alle Indexeinträge neu schreiben und sicherstellen, dass Sie entweder a) sie niemals dem Verbraucher zugänglich machen oder b) niemals behaupten, dass die Nummer zuverlässig ist.

Da wir heute Varchar-Felder haben, besteht der einzige Wert von Varchar (16) gegenüber Varchar (255) darin, dass die DB das Limit von 16 Zeichen für Varchar (16) erzwingt. Wenn das DB-Modell tatsächlich repräsentativ für das physikalische Datenmodell sein soll, können Feldlängen von Wert sein. Wenn es sich jedoch eher um "Speicher" als um ein "Modell UND Speicher" handelt, besteht keinerlei Notwendigkeit.

Dann müssen Sie einfach zwischen einem indizierbaren Textfeld (wie varchar) und einem nicht indizierbaren (wie einem Text- oder CLOB-Feld) unterscheiden. Die indizierbaren Felder haben in der Regel eine Größenbeschränkung, um den Index zu vereinfachen, während die CLOB-Felder dies nicht tun (im Rahmen des Zumutbaren).

Will Hartung
quelle
5

Wenn Sie meiner Erfahrung nach einen Datentyp mit 255 Zeichen zulassen, wird dies von einem dummen Benutzer (oder einem erfahrenen Tester) tatsächlich ausgefüllt.

Dann haben Sie alle möglichen Probleme, einschließlich des Speicherplatzes, den Sie für diese Felder in Berichten und Bildschirmanzeigen in Ihrer Anwendung zulassen. Ganz zu schweigen von der Möglichkeit, das Zeilenlimit für Daten in Ihrer Datenbank zu überschreiten (wenn Sie mehr als einige dieser 255 Zeichenfelder hatten).

Es ist viel einfacher, zu Beginn ein angemessenes Limit auszuwählen und dieses dann über die Anwendung und die Datenbank durchzusetzen.

BradC
quelle
0

Es ist empfehlenswert, nur wenig über das zuzuteilen, was Sie benötigen. Telefonnummern würden niemals so groß werden.

Ein Grund ist, dass, wenn Sie nicht gegen große Einträge validieren, zweifellos jemand alles verwenden wird, was es gibt. Dann könnte Ihnen der Platz in Ihrer Reihe ausgehen. Ich bin mir über das MySQL-Limit nicht sicher, aber 8060 ist die maximale Zeilengröße in MS SQL.

Ein normaler Standardwert wäre 50 imho und würde sich dann erhöhen, wenn dies erforderlich ist.

Taube
quelle
Vielen Dank. Ich stimme definitiv zu, dass es eine gute Praxis ist. Es ist der Leistungsaspekt, den ich wirklich gerne erläutern möchte
Olly
0

In einem MySQL-Kontext kann es wichtig werden, mit Indizes für diese Varchar-Spalten zu arbeiten, da MySQL eine max. Limit von 767 Bytes pro Indexzeile.

Dies bedeutet, dass Sie beim Hinzufügen eines Index über mehrere varchar 255-Spalten diese Grenze für utf8- oder utf8mb4-Spalten ziemlich schnell / sogar schneller erreichen können, wie in den obigen Antworten angegeben

staabm
quelle