it-swarm.com.de

Indexperformance für CHAR vs VARCHAR (Postgres)

In dieser Antwort ( https://stackoverflow.com/questions/517579/strings-as-primary-keys-in-sql-database ) fiel mir eine einzige Bemerkung auf:

Denken Sie auch daran, dass es bei Indexvergleichen oft einen sehr großen Unterschied zwischen einem CHAR und einem VARCHAR gibt

Gilt dies für Postgres?

Ich habe Seiten auf Oracle gefunden, auf denen behauptet wurde, dass CHAR mehr oder weniger ein Alias ​​für VARCHAR ist, und daher ist die Indexleistung dieselbe, aber ich habe bei Postgres nichts Bestimmtes gefunden.

16
LetMeSOThat4U

CHAR und VARCHAR sind in Postgres (und Oracle) genau gleich implementiert. Bei Verwendung dieser Datentypen gibt es keinen Geschwindigkeitsunterschied.

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

Der Vergleich von 100 Zeichen mit 100 Zeichen ist langsamer als der Vergleich 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 einer Länge von 10 Zeichen deklarieren und immer gena 10 Zeichen darin speichern, gibt es absolut keinen Unterschied (dies gilt für Oracle und Postgres).

Der einzige Unterschied besteht also in der Auffüllung, die für den Datentyp char durchgeführt wird.


Denken Sie auch daran, dass es bei Indexvergleichen oft einen sehr großen Unterschied zwischen einem CHAR und einem VARCHAR gibt

Das obige Zitat lautet nur true, wenn (und nur wenn) die Spalte char zu breit definiert ist (d. H. Sie verschwenden Platz aufgrund von Auffüllungen). Wenn die Länge der Spalte char immer vollständig verwendet wird (sodass kein Auffüllen erfolgt), ist das obige Zitat falsch (zumindest für Postgres und Oracle).


Aus meiner Sicht hat der Datentyp char keine echte Word-Verwendung. Verwenden Sie einfach varchar (oder text in Postgres) und vergessen Sie, dass char existiert.

24

Ich bin mit allem einverstanden sagte von a_horse_with_no_name, und ich stimme im Allgemeinen Erwins Kommentar-Rat zu:

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

Metadaten

Mit einer kleinen Ausnahme ist die einzige Zeit, in der ich char() verwende, wenn die Metadaten dies sagen sollen [~ # ~] muss [~ # ~] x-Zeichen haben. Obwohl ich weiß, dass char() sich nur beschwert, wenn die Eingabe über dem Grenzwert liegt, werde ich mich häufig vor Unterläufen in einer CHECK -Einschränkung schützen. Zum Beispiel,

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 manchmal mit Schema-Loadern als Spalte mit fester Breite abgeleitet. Dies kann einen Unterschied in einer Sprache bewirken, die für Zeichenfolgen mit fester Breite optimiert ist.
  2. Es legt eine Konvention fest, die sinnvoll ist und leicht durchgesetzt werden kann. Ich kann einen Schema-Loader in einer Sprache schreiben, um Code aus dieser Konvention zu generieren.

Benötigen Sie ein Beispiel, wo ich das tun kann,

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

Bei Fehlern

Beachten Sie, dass einige Leute sich mit der Inkongruenz von Fehlermeldungen auf beiden Seiten des Limits möglicherweise unwohl fühlen, 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 von fast passt. Verwenden Sie immer text . Sie fragen auch nach varchar(n). Ich benutze das nie . Zumindest kann ich mich nicht erinnern, wann ich das letzte Mal varchar(n) verwendet habe.

  • Wenn eine Spezifikation ein Feld mit statischer Breite hat, dem ich vertraue, verwende ich char(n),
  • Ansonsten verwende ich text, was effektiv varchar ist (keine Begrenzung)

Wenn ich eine Spezifikation mit aussagekräftigen Textschlüsseln variabler Länge finden würde, der ich eine konstante maximale Länge anvertrauen würde, würde ich auch varchar(n) verwenden. Mir fällt jedoch nichts ein, das diesen Kriterien entspricht.

Zusätzliche Bemerkungen

Verwandte Fragen und Antworten:

6
Evan Carroll

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 hat keine Leerzeichen eingefügt.

1
user939857