Indeks wyników dla CHAR vs VARCHAR (Postgres)

16

W tej odpowiedzi ( /programming/517579/strings-as-primary-keys-in-sql-database ) zwróciła moją uwagę jedna uwaga:

Należy również pamiętać, że podczas porównywania indeksów często występuje bardzo duża różnica między CHAR a VARCHAR

Czy dotyczy to / nadal dotyczy Postgres?

Znalazłem strony w Oracle, które twierdzą, że CHARjest to mniej więcej alias, VARCHARwięc wydajność indeksu jest taka sama, ale nie znalazłem nic ostatecznego w Postgres.

LetMeSOThat4U
źródło

Odpowiedzi:

24

CHARi VARCHARsą implementowane dokładnie tak samo w Postgres (i Oracle). Podczas korzystania z tych typów danych nie ma różnicy prędkości.

Jest jednak jedna różnica, która może mieć wpływ na wydajność: charkolumna jest zawsze dopełniana do zdefiniowanej długości. Jeśli więc zdefiniujesz kolumnę jako char(100)i jeden jako, varchar(100)ale przechowujesz tylko 10 znaków w każdej z nich, char(100)kolumna używa 100 znaków dla każdej wartości (10 przechowywanych znaków plus 90 spacji), podczas gdy varcharkolumna przechowuje tylko 10 znaków.

Porównywanie 100 znaków ze 100 znakami będzie wolniejsze niż porównywanie 10 znaków z 10 znakami - chociaż wątpię, czy rzeczywiście można zmierzyć tę różnicę w zapytaniu SQL.

Jeśli zadeklarujesz zarówno długość 10 znaków, jak i zawsze przechowujesz w nich dokładnie 10 znaków, nie ma absolutnie żadnej różnicy (dotyczy to Oracle i Postgres)

Tak więc jedyną różnicą jest wypełnienie dla chartypu danych.


Należy również pamiętać, że podczas porównywania indeksów często występuje bardzo duża różnica między CHAR a VARCHAR

Powyższy cytat jest prawdziwy tylko wtedy, gdy (i tylko wtedy) charkolumna jest zdefiniowana zbyt szeroko (tzn. Marnujesz miejsce z powodu wypełnienia). Jeśli długość charkolumny jest zawsze używana w całości (więc nie występuje wypełnianie), to powyższy cytat jest błędny (przynajmniej dla Postgres i Oracle)


Z mojego punktu widzenia chartyp danych tak naprawdę nie ma zastosowania w prawdziwym słowie. Po prostu użyj varchar(lub textw Postgres) i zapomnij, że charistnieje.

koń bez imienia
źródło
2
Porównywanie 100 znaków ze 100 znakami będzie wolniejsze niż porównywanie 10 znaków z 10 znakami - chociaż wątpię, czy rzeczywiście można zmierzyć tę różnicę w zapytaniu SQL. - W zależności od tego, co robi zapytanie oprócz sortowania, różnica może być ogromna. Właśnie dlatego Postgres 9.5 ma nową funkcję „kluczy skróconych”: pgeoghegan.blogspot.de/2015/01/…
chirlu
6

Zgadzam się ze wszystkim , co powiedział a_horse_with_no_name, i ogólnie zgadzam się z poradą Erwina na komentarz:

Nie, char jest gorszy (i nieaktualny). tekst i varchar działają (prawie) tak samo.

Metadane

Z jednym drobnym wyjątkiem używam tylko wtedy, char()gdy chcę, aby metadane mówiły, że MUSI mieć znaki x. Chociaż wiem, że char()narzeka tylko wtedy, gdy wkład przekroczy limit, często zabezpieczam się przed niedopełnieniem w CHECKograniczeniu. Na przykład,

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

Robię to z kilku powodów,

  1. char(x)jest czasami wywnioskowany z ładujących schematy jako kolumna o stałej szerokości. Może to mieć znaczenie w języku zoptymalizowanym dla ciągów o stałej szerokości.
  2. Ustanawia konwencję, która ma sens i jest łatwa do egzekwowania. Potrafię napisać moduł ładujący schematy w języku, aby wygenerować kod z tej konwencji.

Potrzebujesz przykładu, gdzie mogę to zrobić,

  1. Dwuliterowe skróty stanu, chociaż ponieważ tę listę można wyliczyć, zwykle zrobię to za pomocą ENUM.
  2. Numery identyfikacyjne pojazdu
  3. Numery modeli (o stałym rozmiarze)

O błędach

Zauważ, że niektórzy ludzie mogą czuć się niekomfortowo z niezgodnością komunikatów o błędach po obu stronach limitu, ale nie przeszkadza mi to

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)

Kontrastować z varchar

Co więcej, myślę, że powyższa sugestia bardzo dobrze pasuje do konwencji prawie zawsze używanejtext . Ty też pytasz varchar(n). Nigdy tego nie używam . Przynajmniej nie pamiętam, kiedy ostatni raz użyłem varchar(n).

  • Jeśli specyfikacja ma zaufane pole o statycznej szerokości, używam char(n),
  • W przeciwnym razie używam, textco jest efektywne varchar(bez limitu)

Gdybym znalazł specyfikację z kluczami tekstowymi o zmiennej długości, które były znaczące i że ufałem, że będę mieć stałą maksymalną długość, też bym użył varchar(n). Nie mogę jednak wymyślić niczego, co spełniałoby te kryteria.

Dodatkowe uwagi

Powiązane pytania i odpowiedzi:

Evan Carroll
źródło
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*

Wyrocznia

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 nie padał spacjami.

użytkownik939857
źródło
To tylko złudzenie optyczne w Postgres. SpróbujSELECT pg_column_size(y) FROM x;
dezso,
-2

Znalazłem to najbardziej przydatne i szybkie 3-liniowe objaśnienie:

Z CHAR (n) Vs VARCHAR (N) Vs Tekst w Postgresie

  • Jeśli chcesz zapisać tekst o nieznanej długości, użyj TEXTtypu danych.
  • Jeśli chcesz zapisać tekst o nieznanej długości, ale znasz maksymalną długość, użyj VARCHAR(n).
  • Jeśli chcesz zapisać tekst o znanej dokładnej długości, użyj CHAR(N).
Chwytak
źródło