Indexperformance für CHAR vs VARCHAR (Postgres)


15

In dieser Antwort ( /programming/517579/strings-as-primary-keys-in-sql-database ) fiel mir eine einzige Bemerkung auf:

Denken Sie auch daran, dass es beim Indexvergleich oft einen großen Unterschied zwischen einem CHAR und einem VARCHAR gibt

Gilt das / gilt das noch für Postgres?

Ich habe Seiten auf Oracle gefunden, die behaupten, dass dies CHARmehr oder weniger ein Alias ​​für VARCHARdie gleiche Indexleistung ist, aber auf Postgres habe ich nichts Bestimmtes gefunden.

Antworten:


24

CHARund VARCHARsind in Postgres (und Oracle) genau gleich implementiert. Bei Verwendung dieser Datentypen besteht kein Geschwindigkeitsunterschied.

Es gibt jedoch einen Unterschied, der sich auf die Leistung charauswirken kann : Eine Spalte wird immer auf die festgelegte Länge aufgefüllt. Wenn Sie also eine Spalte als char(100)und eine als definieren, varchar(100)aber jeweils nur 10 Zeichen speichern, verwendet die char(100)Spalte 100 Zeichen für jeden Wert (die 10 Zeichen, die Sie gespeichert haben, plus 90 Leerzeichen), während die varcharSpalte nur 10 Zeichen speichert.

Das Vergleichen von 100 Zeichen mit 100 Zeichen ist langsamer als das Vergleichen von 10 Zeichen mit 10 Zeichen - obwohl ich bezweifle, dass Sie diesen Unterschied in einer SQL-Abfrage tatsächlich messen können.

Wenn Sie beide mit der Länge von 10 Zeichen deklarieren und immer genau 10 Zeichen darin speichern , gibt es überhaupt keinen Unterschied (dies gilt für Oracle und Postgres).

Der einzige Unterschied besteht also in der Auffüllung des charDatentyps.


Denken Sie auch daran, dass es beim Indexvergleich oft einen großen Unterschied zwischen einem CHAR und einem VARCHAR gibt

Das obige Zitat ist nur dann zutreffend, wenn (und nur dann) die charSpalte zu breit definiert ist (dh Sie verschwenden Platz aufgrund von Auffüllung). Wenn die Länge der charSpalte immer vollständig ausgenutzt wird (also keine Auffüllung erfolgt), ist das obige Zitat falsch (zumindest für Postgres und Oracle).


Aus meiner Sicht ist der charDatentyp nicht wirklich wortgetreu. Verwenden Sie einfach varchar(oder textin Postgres) und vergessen Sie, dass es charexistiert.


2
Das Vergleichen von 100 Zeichen mit 100 Zeichen ist langsamer als das Vergleichen von 10 Zeichen mit 10 Zeichen - obwohl ich bezweifle, dass Sie diesen Unterschied in einer SQL-Abfrage tatsächlich messen können. - Abhängig davon, was die Abfrage zusätzlich zum Sortieren macht, kann der Unterschied sehr groß sein. Aus diesem Grund hat Postgres 9.5 eine neue Funktion für abgekürzte Schlüssel: pgeoghegan.blogspot.de/2015/01/…
chirlu

6

Ich stimme allem zu , was a_horse_with_no_name sagt, und ich stimme generell Erwins Kommentar zu:

Nein, char ist minderwertig (und veraltet). text und varchar verhalten sich (fast) gleich.

Metadaten

Mit einer kleinen Ausnahme benutze ich nur dann, char()wenn die Metadaten besagen sollen, dass diese X-Zeichen enthalten MÜSSEN . Obwohl ich weiß, dass sich char()nur beschwert, wenn die Eingabe den Grenzwert überschreitet, werde ich mich häufig vor Unterläufen in einer CHECKEinschränkung schützen . Beispielsweise,

CREATE TABLE foo (
  x char(10) CHECK ( length(x) = 10 )
);
INSERT INTO foo VALUES (repeat('x', 9));

Ich mache das aus ein paar Gründen,

  1. char(x)wird bei Schemaladern manchmal als Spalte mit fester Breite gefolgert. Dies kann einen Unterschied in einer Sprache bewirken, die für Zeichenfolgen mit fester Breite optimiert ist.
  2. Es schafft eine Konvention, die Sinn macht und leicht durchgesetzt werden kann. Ich kann einen Schema-Loader in einer Sprache schreiben, um aus dieser Konvention Code zu generieren.

Brauchen Sie ein Beispiel, wo ich das tun darf,

  1. Zwei-Buchstaben-Abkürzungen, da diese Liste jedoch aufgezählt werden kann, mache ich das normalerweise mit einem ENUM.
  2. Fahrzeugidentifikationsnummern
  3. Modellnummern (feste Größe)

Bei Fehlern

Beachten Sie, dass einige Leute mit der Inkongruenz von Fehlermeldungen auf beiden Seiten des Limits unzufrieden sind, aber es stört mich nicht

test=# INSERT INTO foo VALUES (repeat('x', 9));
ERROR:  new row for relation "foo" violates check constraint "foo_x_check"
DETAIL:  Failing row contains (xxxxxxxxx ).
test=# INSERT INTO foo VALUES (repeat('x', 11));
ERROR:  value too long for type character(10)

Kontrast zu varchar

Darüber hinaus denke ich, dass der obige Vorschlag wirklich gut zu einer Konvention passt, die fast immer verwendet wirdtext . Sie fragen varchar(n)auch nach. Ich benutze das nie . Zumindest kann ich mich nicht an das letzte Mal erinnern, als ich es benutzt habe varchar(n).

  • Wenn eine Spezifikation ein statisches Breitenfeld hat , dass ich vertrauen, ich benutze char(n),
  • Ansonsten nutze ich textwas effektiv ist varchar(no limit)

Wenn ich eine Spezifikation mit aussagekräftigen Textschlüsseln variabler Länge und einer konstanten Maximallänge finden würde, würde ich diese ebenfalls verwenden varchar(n). Mir fällt jedoch nichts ein, was diesen Kriterien entspricht.

Zusätzliche Bemerkungen

Verwandte Fragen und Antworten:


1

Postgresql

sales_reporting_db=# create table x (y char(2));
CREATE TABLE
sales_reporting_db=# insert into x values ('Y');
INSERT 0 1
sales_reporting_db=# select '*' || y || '*' from x;
 ?column? 
----------
 *Y*

Orakel

SQL> create table x ( y char(2));

Table created.

SQL> insert into x values ('Y');

1 row created.

SQL> select '*' || y || '*' from x;

'*'|
----
*Y *

Postgresql füllte nicht mit Leerzeichen auf.


Das ist nur eine optische Täuschung in Postgres. TrySELECT pg_column_size(y) FROM x;
dezso

-2

Ich fand das am nützlichsten und eine schnelle 3-zeilige Erklärung:

Von CHAR (n) Vs VARCHAR (N) Vs Text In Postgres

  • Wenn Sie Text mit unbekannter Länge speichern möchten, verwenden Sie die TEXT Datentyp.
  • Wenn Sie Text mit unbekannter Länge speichern möchten, aber die maximale Länge kennen, verwenden Sie VARCHAR(n) .
  • Wenn Sie Text mit einer bekannten exakten Länge speichern möchten, verwenden Sie CHAR(N).
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.