PostgreSQL: Unterschied zwischen Text und Varchar (Zeichen variieren)


619

Was ist der Unterschied zwischen dem textDatentyp und dem character varying( varchar) Datentyp?

Laut Dokumentation

Wenn die Zeichenvariation ohne Längenangabe verwendet wird, akzeptiert der Typ Zeichenfolgen beliebiger Größe. Letzteres ist eine PostgreSQL-Erweiterung.

und

Darüber hinaus bietet PostgreSQL den Texttyp, in dem Zeichenfolgen beliebiger Länge gespeichert werden. Obwohl der Typentext nicht im SQL-Standard enthalten ist, haben ihn auch einige andere SQL-Datenbankverwaltungssysteme.

Was ist der Unterschied?

Antworten:


745

Es gibt keinen Unterschied, unter der Haube ist alles varlena( Array mit variabler Länge ).

Überprüfen Sie diesen Artikel von Depesz: http://www.depesz.com/index.php/2010/03/02/charx-vs-varcharx-vs-varchar-vs-text/

Ein paar Highlights:

Um alles zusammenzufassen:

  • char (n) - nimmt zu viel Platz in Anspruch, wenn Werte behandelt werden, die kürzer sind als n(füllt sie auf n), und kann aufgrund des Hinzufügens von nachgestellten Leerzeichen zu subtilen Fehlern führen. Außerdem ist es problematisch, den Grenzwert zu ändern
  • varchar (n) - Es ist problematisch, das Limit in der Live-Umgebung zu ändern (erfordert eine exklusive Sperre beim Ändern der Tabelle).
  • varchar - genau wie Text
  • Text - für mich ein Gewinner - über (n) Datentypen, weil es keine Probleme gibt, und über varchar - weil es einen eindeutigen Namen hat

Der Artikel führt detaillierte Tests durch, um zu zeigen, dass die Leistung von Einfügungen und Auswahlen für alle 4 Datentypen ähnlich ist. Außerdem werden alternative Möglichkeiten zum Einschränken der Länge bei Bedarf detailliert beschrieben. Funktionsbasierte Einschränkungen oder Domänen bieten den Vorteil einer sofortigen Erhöhung der Längenbeschränkung. Aufgrund der Tatsache, dass das Verringern einer Zeichenfolgenlängenbeschränkung selten ist, kommt depesz zu dem Schluss, dass eine davon normalerweise die beste Wahl für eine Längenbeschränkung ist.


58
@axiopisty Es ist ein großartiger Artikel. Sie könnten einfach sagen: "Könnten Sie einige Auszüge ziehen, falls der Artikel jemals ausfällt?" Ich habe versucht, den Inhalt / die Schlussfolgerungen des Artikels kurz zusammenzufassen. Ich hoffe, dies reicht aus, um Ihre Bedenken auszuräumen.
jpmc26

34
@axiopisty, genau genommen, lautete die erste Antwort " unter der Haube ist alles Varlena ", was sicherlich nützliche Informationen sind, die diese Antwort von einer Nur-Link-Antwort unterscheiden.
Bruno

24
Eine Sache, die Sie bei einer unbegrenzten Zeichenfolge beachten sollten, ist, dass sie das Potenzial für Missbrauch eröffnen. Wenn Sie einem Benutzer erlauben, einen Nachnamen beliebiger Größe zu haben, speichert möglicherweise jemand GROSSE Informationsmengen in Ihrem Nachnamenfeld. In einem Artikel über die Entwicklung von reddit geben sie den Rat, "alles zu begrenzen".
Mark Hildreth

7
@MarkHildreth Guter Punkt, obwohl solche Einschränkungen heutzutage in einer Anwendung im Allgemeinen weiter durchgesetzt werden - damit die Regeln (und versuchten Verstöße / Wiederholungsversuche) von der Benutzeroberfläche reibungslos behandelt werden können. Wenn jemand solche Dinge in der Datenbank noch tun möchte, kann er Einschränkungen verwenden. Siehe blog.jonanin.com/2013/11/20/postgresql-char-varchar, das "ein Beispiel für die Verwendung von TEXT und Einschränkungen zum Erstellen von Feldern mit mehr Flexibilität als VARCHAR" enthält.
Ethan

4
@Ethan blog.jonanin.com/2013/11/20/postgresql-char-varchar -> Dies ist nicht verfügbar, aber hier zu finden. Archive.is/6xhA5 .
MrR

115

Als „ Zeichentypen “ in der Dokumentation weist darauf hin, varchar(n), char(n), und textsind alle auf die gleiche Weise gespeichert. Der einzige Unterschied besteht darin, dass zusätzliche Zyklen erforderlich sind, um die Länge zu überprüfen, falls eine angegeben ist, und den zusätzlichen Platz und die zusätzliche Zeit, die erforderlich sind, wenn eine Polsterung erforderlich ist char(n).

Wenn Sie jedoch nur ein einzelnes Zeichen speichern müssen, bietet die Verwendung des speziellen Typs einen geringfügigen Leistungsvorteil "char"(behalten Sie die doppelten Anführungszeichen bei - sie sind Teil des Typnamens). Sie erhalten einen schnelleren Zugriff auf das Feld und es gibt keinen Overhead zum Speichern der Länge.

Ich habe gerade eine Tabelle mit 1.000.000 Zufällen erstellt, "char"die aus dem Kleinbuchstaben ausgewählt wurden. Eine Abfrage zum Abrufen einer Häufigkeitsverteilung ( select count(*), field ... group by field) dauert ungefähr 650 Millisekunden, gegenüber ungefähr 760 für dieselben Daten unter Verwendung eines textFelds.


18
Technisch gesehen sind die Anführungszeichen nicht Teil des Typnamens. Sie werden benötigt, um es vom Schlüsselwort char zu unterscheiden.
Jasen

31
Technisch sind Sie richtig @Jasen ... Was natürlich die beste Art von richtig ist
JohannesH

Datentyp "char" ist nicht char? Es ist heutzutage gültig für PostgreSQL 11+? ... Ja: "Der Typ "char"(beachten Sie die Anführungszeichen) unterscheidet sich von char (1) darin, dass nur ein Byte Speicher verwendet wird. Er wird intern in den Systemkatalogen als vereinfachter Aufzählungstyp verwendet ." , Leitfaden / Datentyp-Zeichen .
Peter Krauss

63

AKTUALISIERUNG DER BENCHMARKS FÜR 2016 (S. 9,5 +)

Und mit "Pure SQL" -Benchmarks (ohne externes Skript)

  1. Verwenden Sie einen beliebigen string_generator mit UTF8

  2. Hauptbenchmarks:

    2.1. EINFÜGEN

    2.2. SELECT Vergleichen und Zählen


CREATE FUNCTION string_generator(int DEFAULT 20,int DEFAULT 10) RETURNS text AS $f$
  SELECT array_to_string( array_agg(
    substring(md5(random()::text),1,$1)||chr( 9824 + (random()*10)::int )
  ), ' ' ) as s
  FROM generate_series(1, $2) i(x);
$f$ LANGUAGE SQL IMMUTABLE;

Spezifischen Test vorbereiten (Beispiele)

DROP TABLE IF EXISTS test;
-- CREATE TABLE test ( f varchar(500));
-- CREATE TABLE test ( f text); 
CREATE TABLE test ( f text  CHECK(char_length(f)<=500) );

Führen Sie einen Basistest durch:

INSERT INTO test  
   SELECT string_generator(20+(random()*(i%11))::int)
   FROM generate_series(1, 99000) t(i);

Und andere Tests,

CREATE INDEX q on test (f);

SELECT count(*) FROM (
  SELECT substring(f,1,1) || f FROM test WHERE f<'a0' ORDER BY 1 LIMIT 80000
) t;

... und verwenden EXPLAIN ANALYZE.

WIEDER AKTUALISIERT 2018 (S. 10)

wenig bearbeiten, um die Ergebnisse von 2018 hinzuzufügen und Empfehlungen zu verstärken.


Ergebnisse in 2016 und 2018

Meine Ergebnisse nach dem Durchschnitt in vielen Maschinen und vielen Tests: alle gleich
(statistisch weniger als die Standardabweichung).

Empfehlung

  • Verwenden Sie den textDatentyp,
    vermeiden Sie alte, varchar(x)da dies manchmal kein Standard ist, z . B. in den CREATE FUNCTIONAbschnitten varchar(x)varchar(y) .

  • ausdrückliche Grenzen (bei gleicher varcharLeistung!) durch mit CHECKKlausel in der CREATE TABLE
    z CHECK(char_length(x)<=10).
    Mit einem vernachlässigbaren Leistungsverlust in INSERT / UPDATE können Sie auch Bereiche und String-Strukturen steuern,
    zCHECK(char_length(x)>5 AND char_length(x)<=20 AND x LIKE 'Hello%')


Es spielt also keine Rolle, ob ich alle meine Spalten varchar anstelle von Text gemacht habe? Ich habe die Länge nicht angegeben, obwohl einige nur 4 - 5 Zeichen und schon gar nicht 255 sind.
Graben

1
@ Trench ja, es spielt keine Rolle
FuriousFolder

1
cool, ich habe es aus Sicherheitsgründen überarbeitet und trotzdem alles geschrieben. Es hat gut funktioniert und es war sowieso super einfach, schnell Millionen von historischen Aufzeichnungen hinzuzufügen.
Graben

@trench und Leser: Die einzige Ausnahme ist der schnellere Datentyp "char", die nicht ist char, auch in heute von PostgreSQL 11+. Wie das Handbuch / Datentyp-Zeichen sagt "Der Typ "char"(beachten Sie die Anführungszeichen) unterscheidet sich von char (1) darin, dass er nur ein Byte Speicher verwendet. Er wird intern in den Systemkatalogen als vereinfachter Aufzählungstyp verwendet ." .
Peter Krauss

3
noch gültig mit pg11 im Jahr 2019: text> varchar (n)> text_check> char (n)
Olivier Refalo

37

Im PostgreSQL-Handbuch

Es gibt keinen Leistungsunterschied zwischen diesen drei Typen, abgesehen von erhöhtem Speicherplatz bei Verwendung des mit Leerzeichen aufgefüllten Typs und einigen zusätzlichen CPU-Zyklen zur Überprüfung der Länge beim Speichern in einer Spalte mit eingeschränkter Länge. Während Zeichen (n) in einigen anderen Datenbanksystemen Leistungsvorteile bietet, gibt es in PostgreSQL keinen solchen Vorteil. Tatsächlich ist Zeichen (n) aufgrund seiner zusätzlichen Speicherkosten normalerweise das langsamste der drei. In den meisten Situationen sollten stattdessen unterschiedliche Texte oder Zeichen verwendet werden.

Ich benutze normalerweise Text

Referenzen: http://www.postgresql.org/docs/current/static/datatype-character.html


23

Meiner Meinung nach varchar(n)hat es seine eigenen Vorteile. Ja, sie alle verwenden denselben zugrunde liegenden Typ und all das. Es sollte jedoch darauf hingewiesen werden, dass Indizes in PostgreSQL eine Größenbeschränkung von 2712 Bytes pro Zeile haben.

TL; DR: Wenn Sie einen textTyp ohne Einschränkung verwenden und Indizes für diese Spalten haben, ist es sehr wahrscheinlich, dass Sie diese Grenze für einige Ihrer Spalten erreichen und beim Versuch, Daten einzufügen, eine Fehlermeldung erhalten. Mit der Verwendung varchar(n)können Sie dies jedoch verhindern.

Weitere Details: Das Problem hierbei ist, dass PostgreSQL beim Erstellen von Indizes für den textTyp oder varchar(n)bei einem nWert größer als 2712 keine Ausnahmen angibt. Es wird jedoch ein Fehler ausgegeben, wenn versucht wird, einen Datensatz mit einer komprimierten Größe von mehr als 2712 einzufügen. Dies bedeutet, dass Sie leicht 100.000 Zeichen Zeichenfolgen einfügen können, die aus sich wiederholenden Zeichen bestehen, da diese weit unter 2712 komprimiert werden. Sie können jedoch möglicherweise keine Zeichenfolgen mit 4000 Zeichen einfügen, da die komprimierte Größe größer als 2712 Byte ist. Wenn Sie verwenden, varchar(n)wo nnicht zu viel größer als 2712 ist, sind Sie vor diesen Fehlern sicher.


Spätere Postgres-Fehler beim Versuch, eine Indizierung für Text zu erstellen, funktionieren nur für varchar (Version ohne (n)). Nur mit eingebetteten Postgres getestet.
Arntg

2
Verweis auf: stackoverflow.com/questions/39965834/… mit einem Link zum PostgreSQL-Wiki: wiki.postgresql.org/wiki/… hat eine maximale Zeilengröße von 400 GB, daher scheint das angegebene Limit von 2712 Byte pro Zeile falsch zu sein . Maximale Größe für eine Datenbank? unbegrenzt (32 TB Datenbanken vorhanden) Maximale Größe für eine Tabelle? 32 TB Maximale Größe für eine Reihe? 400 GB Maximale Größe für ein Feld? 1 GB Maximale Anzahl von Zeilen in einer Tabelle? unbegrenzt
Bill Worthington

@ BillWorthington Die von Ihnen veröffentlichten Zahlen berücksichtigen jedoch nicht das Setzen von Indizes. Bei 2712 Byte handelt es sich um die Höchstgrenzen von btree. Es handelt sich um ein Implementierungsdetail, sodass Sie es nicht in den Dokumenten finden können. Sie können es jedoch ganz einfach selbst testen oder einfach googeln, indem Sie nach "Postgresql-Indexzeilengröße überschreitet maximal 2712 für Index" suchen, z.
SOTN

Ich bin neu in PostgeSQL, also nicht der Experte. Ich arbeite an einem Projekt, in dem ich Nachrichtenartikel in einer Spalte in einer Tabelle speichern möchte. Es sieht so aus, als würde ich den Textspaltentyp verwenden. Eine Gesamtzeilengröße von 2712 Byte klingt viel zu niedrig für eine Datenbank, von der angenommen wird, dass sie nahe an der Ebene von Oracle liegt. Verstehe ich Sie richtig, dass Sie sich auf die Indizierung eines großen Textfelds beziehen? Nicht versuchen, dich herauszufordern oder mit dir zu streiten, sondern nur versuchen, die wirklichen Grenzen zu verstehen. Wenn keine Indizes beteiligt sind, würde das Zeilenlimit dann 400 GB betragen, wie im Wiki? Danke für die schnelle Rückmeldung.
Bill Worthington

1
@ BillWorthington Sie sollten über die Volltextsuche recherchieren. Überprüfen Sie diesen Link zB
sotn

18

Text und Varchar haben unterschiedliche implizite Typkonvertierungen. Die größte Auswirkung, die mir aufgefallen ist, ist der Umgang mit nachgestellten Leerzeichen. Beispielsweise ...

select ' '::char = ' '::varchar, ' '::char = ' '::text, ' '::varchar = ' '::text

kehrt zurück true, false, trueund nicht true, true, truewie erwartet.


Wie ist das möglich? Wenn a = b und a = c, dann ist b = c.
Lucas Silva

4

Etwas OT: Wenn Sie Rails verwenden, kann die Standardformatierung von Webseiten unterschiedlich sein. Bei Dateneingabeformularen können textFelder gescrollt werden, character varying(Schienen- string) Felder sind jedoch einzeilig. Showansichten sind so lang wie nötig.


2

Eine gute Erklärung von http://www.sqlines.com/postgresql/datatypes/text :

Der einzige Unterschied zwischen TEXT und VARCHAR (n) besteht darin, dass Sie die maximale Länge einer VARCHAR-Spalte begrenzen können. In VARCHAR (255) ist es beispielsweise nicht möglich, eine Zeichenfolge mit mehr als 255 Zeichen einzufügen.

Sowohl TEXT als auch VARCHAR haben die Obergrenze bei 1 GB, und es gibt keinen Leistungsunterschied zwischen ihnen (gemäß der PostgreSQL-Dokumentation).


-1

character varying(n), varchar(n)- (beide gleich). Der Wert wird auf n Zeichen gekürzt, ohne dass ein Fehler auftritt.

character(n), char(n)- (beide gleich). feste Länge und wird bis zum Ende der Länge mit Leerzeichen aufgefüllt.

text- Unbegrenzte Länge.

Beispiel:

Table test:
   a character(7)
   b varchar(7)

insert "ok    " to a
insert "ok    " to b

Wir bekommen die Ergebnisse:

a        | (a)char_length | b     | (b)char_length
----------+----------------+-------+----------------
"ok     "| 7              | "ok"  | 2

5
Während MySQL die Daten stillschweigend abschneidet, wenn der Wert die Spaltengröße überschreitet, wird PostgreSQL den Fehler "Wert zu lang für Typzeichen variierend (n)" nicht auslösen.
Gsiems
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.