MySQL: Großes VARCHAR vs. TEXT?

845

Ich habe eine Nachrichtentabelle in MySQL, die Nachrichten zwischen Benutzern aufzeichnet. Abgesehen von den typischen IDs und Nachrichtentypen (alle Ganzzahltypen) muss ich den eigentlichen Nachrichtentext entweder als VARCHAR oder als TEXT speichern. Ich setze ein Front-End-Limit von 3000 Zeichen, was bedeutet, dass die Nachrichten niemals so lange in die Datenbank eingefügt werden.

Gibt es eine Begründung für VARCHAR (3000) oder TEXT? Es ist etwas, nur VARCHAR (3000) zu schreiben, das sich etwas kontraintuitiv anfühlt. Ich habe andere ähnliche Beiträge zu Stack Overflow gelesen, wäre aber gut, um Ansichten zu erhalten, die für diese Art der allgemeinen Nachrichtenspeicherung spezifisch sind.

Tom
quelle
27
Ein bisschen alt, aber ich bin hierher gekommen, weil ich auf ein Problem gestoßen bin, das mich dazu gebracht hat, darüber nachzudenken. In meinem Fall war mein Front-End-Formular auf 2.000 Zeichen beschränkt, aber die in meiner Speichermethode implizierte Codierung codierte internationale Zeichen als mehrere Zeichen (die anscheinend zwischen 3 und 12 pro Zeichen liegen können). So werden meine 2.000 plötzlich bis zu 24.000. Etwas zum Nachdenken ...
James S
3
Ich habe festgestellt, dass Text für viele gleichzeitige Einfügungen erheblich schneller ist.
Ray S.
1
@ JamesS: utf8mb4 ...>. <
unteilbar
10
@ RickJames erwägen, eine aktualisierte Antwort zu veröffentlichen, anstatt die Frage zu schließen
Yvette
3
@YvetteColomb - Ich habe eine Antwort hinzugefügt. Ich möchte hauptsächlich die akzeptierte Antwort loswerden, weil sie veraltet ist . Ich kam zu den Fragen und Antworten, weil jemand falsche Informationen zitierte und sagte "754 Upvotes, also muss es richtig sein". OK, ich habe auch die genehmigte Antwort bearbeitet. (Obwohl sich das unangemessen anfühlt.)
Rick James

Antworten:

811
  • TEXTund BLOB kann durch Speichern außerhalb der Tabelle, wobei die Tabelle nur einen Zeiger auf den Ort des tatsächlichen Speichers aufweist. Wo es gespeichert wird, hängt von vielen Faktoren wie Datengröße, Spaltengröße, Zeilenformat und MySQL-Version ab.

  • VARCHARwird inline mit der Tabelle gespeichert. VARCHARist schneller, wenn die Größe angemessen ist, deren Kompromiss schneller von Ihren Daten und Ihrer Hardware abhängt. Sie möchten ein reales Szenario mit Ihren Daten vergleichen.

MindStalker
quelle
148
+1: VARCHAR (inline gespeichert) ist normalerweise schneller, wenn die Daten häufig abgerufen werden (in den meisten Abfragen enthalten). Für ein großes Datenvolumen, das normalerweise nicht abgerufen wird (dh von keiner Abfrage referenziert wird), ist es möglicherweise besser, die Daten nicht inline zu speichern. Für inline gespeicherte Daten gibt es eine Obergrenze für die Zeilengröße.
Spencer7593
21
@Pacerier: Der genaue Vorteil der Vermeidung von "Inline" -Speicher besteht in einer Erhöhung der Anzahl der Zeilen, die in einem Block gespeichert werden können. Dies bedeutet, dass die Tabellenzeilen weniger Blöcke im InnoDB-Puffercache belegen (geringerer Speicherbedarf) und weniger Blöcke, die auf und von der Festplatte übertragen werden sollen (reduzierte E / A). Dies ist jedoch nur dann ein Leistungsvorteil, wenn die "außerhalb der Zeile" gespeicherten Spalten von Abfragen weitgehend nicht referenziert werden. Wenn die meisten Abfragen auf diese Spalten außerhalb der Zeile verweisen, wird dieser Vorteil weitgehend verflogen. Inline wird bevorzugt, wenn die Spalten in die maximale Zeilengröße passen und häufig referenziert werden.
Spencer7593
231
"VARCHAR ist schneller, wenn die Größe angemessen ist". Was ist eine "vernünftige" Anzahl von Zeichen, 100? 1000? 100.000?
Tim Peterson
125
Diese Antwort ist für InnoDB nicht korrekt. Sowohl VARCHAR als auch BLOB / TEXT werden inline mit anderen Spalten gespeichert, wenn der Wert in einer bestimmten Zeile in die Seitengröße passt (16 KB und jede Seite muss mindestens zwei Zeilen enthalten). Wenn die Zeichenfolge dafür zu groß ist, werden zusätzliche Seiten angezeigt. Eine ausführliche Erklärung finden Sie unter mysqlperformanceblog.com/2010/02/09/blob-storage-in-innodb .
Bill Karwin
14
@ BillKarwin ... Wenn ich das richtig verstehe, sollte es keinen Leistungsunterschied zwischen varcharund blob/ textin InnoDB für kleine Textelemente geben? So wäre es dann sinnvoll sein , nur jeder macht varchareine textArt und lassen Sie die DB den Inline vs. Überlauf zu verwalten?
Ryvantage
473

Können Sie vorhersagen, wie lange die Benutzereingabe dauern würde?

VARCHAR (X)

Fall: Benutzername, E-Mail, Land, Betreff, Passwort


TEXT

Fall: Nachrichten, E-Mails, Kommentare, formatierter Text, HTML, Code, Bilder, Links


MEDIUMTEXT

Fall: große json Körper, kurze bis mittellange Bücher, CSV-Saiten


LONGTEXT

Fallbeispiel: Lehrbücher, Programme, jahrelange Protokolldateien, Harry Potter und der Feuerkelch, Protokollierung wissenschaftlicher Forschung

Michael J. Calkins
quelle
7
Vorhersehbarkeit ist hier wirklich ein Nebeneffekt. Es ist tatsächlich die maximal erwartete Länge, die der entscheidende Faktor sein sollte. Die Elemente, die Sie als vorhersehbarer erwähnen, sind nur so, weil sie kürzer als die anderen sind.
Andrew Barber
29
@ Andrew-Barber Das ist aber mein Punkt. Alle anderen Beiträge erklären gut die Unterschiede, aber nicht die Situationen, in denen Sie tatsächlich eine Wahl zwischen den beiden treffen müssen. Ich habe versucht darauf hinzuweisen, dass die Verwendung von varchar für vorhersehbar kurz eine gute Wahl ist und die Verwendung von Text für beliebig lange eine gute Wahl ist.
Michael J. Calkins
1
Wenn alle Spalten kurz und vorhersehbar sind (z. B. MAC-Adresse, IMEI usw. sind Dinge, die sich nie ändern), verwenden Sie CHAR-Spalten, und Sie können Ihre Zeilengröße festlegen, was die Verwendung von MyISAM möglicherweise erheblich beschleunigen sollte auch InnoDb, obwohl ich mir nicht sicher bin.
Matt
1
@ MichaelJ.Calkins Was in MySQL 5.6 passiert ist. Jetzt haben Sie auch die Volltextsuche in InnoDB. Siehe dev.mysql.com/doc/refman/5.6/en/fulltext-search.html
PhoneixS
7
Zeichenbeschränkungen: TINYTEXT: 255; TEXT: 65.535; MEDIUMTEXT: 16.777.215; LONGTEXT: 4,294,967,29.
Victor Stoddard
218

Nur um die Best Practice zu klären:

  1. Textformatnachrichten sollten fast immer als TEXT gespeichert werden (sie sind beliebig lang).

  2. Zeichenfolgenattribute sollten als VARCHAR gespeichert werden (der Zielbenutzername, der Betreff usw.).

Ich verstehe, dass Sie ein Front-End-Limit haben, das großartig ist, bis es nicht mehr ist. * grins * Der Trick besteht darin, sich die Datenbank als getrennt von den Anwendungen vorzustellen, die eine Verbindung zu ihr herstellen. Nur weil eine Anwendung die Daten begrenzt, bedeutet dies nicht, dass die Daten an sich begrenzt sind.

Was ist mit den Nachrichten selbst, das sie zwingt, niemals mehr als 3000 Zeichen zu sein? Wenn es sich nur um eine beliebige Anwendungsbeschränkung handelt (z. B. für ein Textfeld oder etwas anderes), verwenden Sie ein TEXTFeld auf der Datenebene.

James
quelle
Was bedeutet "was großartig ist, bis es nicht mehr ist"? Worauf bezieht sich "nicht"?
Pacerier
7
@Pacerier Um Ihnen ein Beispiel für das "Nicht" zu geben, über das James wahrscheinlich spricht: Nehmen Sie zum Beispiel Twitter, das bis vor kurzem ein Limit von 140 Zeichen für PMs hatte. Sie entschieden, dass dies nicht mehr sinnvoll war und beschlossen, diese Grenze vollständig aufzuheben. Wenn sie nicht darüber nachgedacht hätten (was ich mir ziemlich sicher bin, dass sie es wahrscheinlich getan haben ...), wären sie auf das oben beschriebene Szenario gestoßen.
PaulSkinner
9
Ich richte gerade unsere neue Datenbank ein, und ich hatte angenommen, dass niemand mehr als 2000 Zeichen in unsere winzigen Kommentarfelder einfügen könnte, und dann, wie James bemerkt, war es heute Abend plötzlich "nicht in Ordnung", weil ein Benutzer eine Sehr gültiger Kommentar mit einer Länge von 2600 Zeichen. Ich hatte varchar (2000) verwendet, weil ich dachte, es könnte unmöglich länger werden, und ich habe mich geirrt. Also ja, es ist großartig, bis es nicht mehr so ​​ist. In unserem Fall dauerte die Manifestation nur wenige Tage. Die folgende Regel, Michael J. Calkins, werde ich von nun an anwenden. Text für Nachrichten, Kommentare.
Lizardx
1
@ Pacerier "was großartig ist, bis es nicht mehr großartig ist". Mit anderen Worten, es funktioniert fast immer und ist wunderbar ... außer in Ausnahmefällen, in denen es nicht so toll ist.
Begrenzte Versöhnung
@Pacerier Ein weiteres interessantes Beispiel wird in den Kommentaren der ausgewählten Antwort erwähnt. Grundsätzlich hatte er ein Front-End-Limit von 2.000 Zeichen, aber die eingeführten Zeichen befanden sich auf einer Codepage, die in Wirklichkeit mehr Bytes als normale Buchstaben verwendete. Seine Datenbank benötigte schließlich Speicherplatz für 24k Zeichen, nur weil er die tatsächliche Bytegröße der eingeführten Zeichen berücksichtigen musste.
RaptorX
32

Haftungsausschluss: Ich bin kein MySQL-Experte ... aber dies ist mein Verständnis der Probleme.

Ich denke, TEXT wird außerhalb der MySQL-Zeile gespeichert, während ich denke, dass VARCHAR als Teil der Zeile gespeichert ist. Es gibt eine maximale Zeilenlänge für MySQL-Zeilen. Sie können also mithilfe von VARCHAR begrenzen, wie viele andere Daten Sie in einer Zeile speichern können.

Da VARCHAR Teil der Zeile ist, vermute ich, dass Abfragen, die dieses Feld betrachten, etwas schneller sind als Abfragen, die einen TEXT-Block verwenden.

Michael Anderson
quelle
38
Die Zeilenlängenbeschränkung beträgt 65.535 Byte [ dev.mysql.com/doc/refman/5.0/de/column-count-limit.html ]. Wenn Ihre Spalte utf8-codiert ist, bedeutet dies, dass eine varcharSpalte mit 3000 Zeichen bis zu 9000 Byte aufnehmen kann.
Jan Fabry
7
UTF-8-Zeichen können bis zu 4 Byte lang sein. Ich denke, Sie haben 12.000 Byte gemeint (es sei denn, es gibt eine MySQL-Sache, die ich hier nicht verstehe).
Raylu
13
@raylu MySQLs UTF-8 ist insofern "gefälschtes UTF-8", als es maximal 3 Bytes pro Zeichen unterstützt. Daher gibt es keine Möglichkeit, Unicode-Zeichen direkt außerhalb der BMP-Ebene in MySQLs UTF-8 zu speichern. Dies ist in MySQL 5.5 behoben.
Pacerier
2
Ich glaube, dass diese Behauptung nur für MyISAM gilt. Ich kann keine endgültige Quelle finden, aber ich glaube, dass InnoDB auch TEXTInline in der Tabelle speichert .
Dotancohen
2
@dotancohen Ich habe hier eine Quelle gefunden, die erklärt, dass das Speichern von Daten variabler Länge mit InnoDB variieren kann (kann extern oder inline innerhalb der Zeile gespeichert werden). mysqlserverteam.com/externally-stored-fields-in-innodb
KiX Ortillan
30

Kurze Antwort: Kein praktischer, Leistungs- oder Speicherunterschied.

Lange Antwort:

Es gibt im Wesentlichen keinen Unterschied (in MySQL) zwischen VARCHAR(3000)(oder einem anderen großen Limit) und TEXT. Ersteres wird bei 3000 Zeichen abgeschnitten ; Letzteres wird bei 65535 Bytes abgeschnitten . (Ich unterscheide zwischen Bytes und Zeichen, da ein Zeichen mehrere Bytes aufnehmen kann.)

Für kleinere Grenzwerte VARCHARgibt es einige Vorteile gegenüber TEXT.

  • "kleiner" bedeutet 191, 255, 512, 767 oder 3072 usw., abhängig von Version, Kontext und CHARACTER SET.
  • INDEXessind darauf beschränkt, wie groß eine Spalte indiziert werden kann. (767 oder 3072 Bytes ; dies ist abhängig von der Version und den Einstellungen)
  • Von complex erstellte Zwischentabellen SELECTswerden auf zwei verschiedene Arten behandelt: MEMORY (schneller) oder MyISAM (langsamer). Wenn es sich um 'große' Spalten handelt, wird die langsamere Technik automatisch ausgewählt. (Wesentliche Änderungen in Version 8.0; Änderungen an diesem Aufzählungszeichen vorbehalten.)
  • In Bezug auf das vorherige Element springen alle TEXTDatentypen (im Gegensatz zu VARCHAR) direkt zu MyISAM. Das heißt, TINYTEXTist für generierte temporäre Tabellen automatisch schlechter als das Äquivalent VARCHAR. (Aber das führt die Diskussion in eine dritte Richtung!)
  • VARBINARYist wie VARCHAR; BLOBist wie TEXT.

Gegenargument zu anderen Antworten

Bei der ursprünglichen Frage wurde eine Frage gestellt (welcher Datentyp verwendet werden soll). Die akzeptierte Antwort beantwortete etwas anderes (Off-Record-Speicher). Diese Antwort ist jetzt veraltet.

Als dieser Thread gestartet und beantwortet wurde, gab es in InnoDB nur zwei "Zeilenformate". Bald darauf wurden zwei weitere Formate ( DYNAMICund COMPRESSED) eingeführt.

Der Speicherort für TEXTund VARCHAR()basiert auf der Größe und nicht auf dem Namen des Datentyps . Eine aktualisierte Beschreibung der On / Off-Record-Speicherung großer Text- / Blob-Spalten finden Sie hier .

Rick James
quelle
1
Einige gute Einblicke hier. Dies sollte die akzeptierte Antwort sein.
Kosta Kontos
2
@KostaKontos - Danke für das Lob und den Tippfehler. Wenn ich die Notwendigkeit einer besseren Antwort sehe, werde ich eine Antwort hinzufügen, auch wenn 8 Jahre und 800 Upvotes zu spät sind.
Rick James
7

Die vorhergehenden Antworten bestehen nicht genug auf dem Hauptproblem: selbst bei sehr einfachen Fragen wie

(SELECT t2.* FROM t1, t2 WHERE t2.id = t1.id ORDER BY t1.id) 

Eine temporäre Tabelle kann erforderlich sein. Wenn ein VARCHARFeld betroffen ist, wird es in ein CHARFeld in der temporären Tabelle konvertiert . Wenn Sie also in Ihrer Tabelle 500 000 Zeilen mit einem VARCHAR(65000)Feld angeben , verwendet diese Spalte allein 6,5 * 5 * 10 ^ 9 Byte. Solche temporären Tabellen können nicht im Speicher verarbeitet werden und werden auf die Festplatte geschrieben. Die Auswirkungen sind voraussichtlich katastrophal.

Quelle (mit Metriken): https://nicj.net/mysql-text-vs-varchar-performance/ (Dies bezieht sich auf die Behandlung von TEXTvs VARCHARin der "Standard" (?) MyISAM-Speicher-Engine. In anderen kann es anders sein, zB InnoDB.)

Max
quelle
3
InnoDB: Gleiches gilt für Version 5.7. Mit 8.0 sind die Varchar-Temperaturen variabel lang.
Rick James
3

Es gibt einen RIESIGEN Unterschied zwischen VARCHAR und TEXT. Während VARCHAR-Felder indiziert werden können, können TEXT-Felder nicht. Felder vom Typ VARCHAR werden inline gespeichert, während TEXT offline gespeichert wird. In den Datensätzen werden nur Zeiger auf TEXT-Daten gespeichert.

Wenn Sie Ihr Feld für eine schnellere Suche, Aktualisierung oder Löschung indizieren müssen, wählen Sie VARCHAR, egal wie groß es ist. Ein VARCHAR (10000000) ist niemals dasselbe wie ein TEXT-Feld, da diese beiden Datentypen unterschiedlicher Natur sind.

  • Wenn Sie Ihr Feld nur zur Archivierung verwenden
  • Sie interessieren sich nicht für das Abrufen der Datengeschwindigkeit
  • Sie legen Wert auf Geschwindigkeit, verwenden jedoch den Operator '% LIKE%' in Ihrer Suchanfrage, sodass die Indizierung nicht viel hilft
  • Sie können keine Begrenzung der Datenlänge vorhersagen

als für TEXT gehen.

Viktor Joras
quelle
Teilweise irreführende Informationen: TEXT-Spalten können nicht vollständig indexiert werden. Wenn Sie eine TEXT-Spalte in den Index aufnehmen, müssen Sie die Länge angeben. Auch VARCHARs können bei VARCHARs> 255 nicht vollständig indiziert werden, da die Indexgröße eine maximale Länge hat.
eRadical
2

Varchar ist für kleine Daten wie E-Mail-Adressen gedacht, während Text für viel größere Daten wie Nachrichtenartikel und Blob für Binärdaten wie Bilder.

Die Leistung von Varchar ist leistungsfähiger, da es vollständig aus dem Speicher ausgeführt wird. Dies ist jedoch nicht der Fall, wenn die Daten beispielsweise zu groß sind varchar(4000).

Text hingegen bleibt nicht im Speicher haften und wird durch die Festplattenleistung beeinträchtigt. Sie können dies jedoch vermeiden, indem Sie Textdaten in einer separaten Tabelle trennen und eine Abfrage für die linke Verknüpfung anwenden, um Textdaten abzurufen.

Blob ist viel langsamer, verwenden Sie es also nur, wenn Sie nicht viele Daten wie 10000 Bilder haben, die 10000 Datensätze kosten.

Befolgen Sie diese Tipps für maximale Geschwindigkeit und Leistung:

  1. Verwenden Sie varchar für Namen, Titel und E-Mails

  2. Verwenden Sie Text für große Datenmengen

  3. Separaten Text in verschiedenen Tabellen

  4. Verwenden Sie Linksverknüpfungsabfragen für eine ID, z. B. eine Telefonnummer

  5. Wenn Sie Blob verwenden möchten, wenden Sie die gleichen Tipps wie im Text an

Dadurch kosten Abfragen Millisekunden für Tabellen mit Daten> 10 M und einer garantierten Größe von bis zu 10 GB.

Creative87
quelle