PostgreSQL: Różnica między tekstem a varcharem (różne znaki)


619

Jaka jest różnica między text typem danych a character varying( varchar) typami danych?

Według z dokumentacją

Jeśli zmienna znakowa jest używana bez specyfikatora długości, typ akceptuje łańcuchy o dowolnym rozmiarze. To drugie jest rozszerzeniem PostgreSQL.

i

Ponadto PostgreSQL zapewnia typ tekstu, który przechowuje ciągi dowolnej długości. Chociaż tekst typu nie jest w standardzie SQL, ma go również kilka innych systemów zarządzania bazami danych SQL.

Jaka jest różnica?

Odpowiedzi:


745

Nie ma różnicy, pod maską jest wszystko varlena( tablica o zmiennej długości ).

Sprawdź ten artykuł z Depesz: http://www.depesz.com/index.php/2010/03/02/charx-vs-varcharx-vs-varchar-vs-text/

Kilka najważniejszych:

Podsumowując:

  • char (n) - zajmuje zbyt dużo miejsca w przypadku wartości krótszych niż n( nuzupełnia je ) i może prowadzić do subtelnych błędów z powodu dodania spacji końcowych, a także zmiana granicy jest problematyczna
  • varchar (n) - problematyczne jest zmienianie limitu w środowisku na żywo (wymaga wyłącznej blokady podczas zmiany tabeli)
  • varchar - tak jak tekst
  • tekst - dla mnie zwycięzca - ponad (n) typami danych, ponieważ brakuje im ich problemów, a ponad varchar - ponieważ ma odrębną nazwę

W artykule przeprowadzono szczegółowe testy, aby wykazać, że wydajność wstawiania i selekcji dla wszystkich 4 typów danych jest podobna. Szczegółowo przygląda się również alternatywnym sposobom ograniczania długości w razie potrzeby. Wiązania lub domeny oparte na funkcjach mają tę zaletę, że natychmiastowe zwiększenie ograniczenia długości, a na podstawie tego, że zmniejszenie ograniczenia długości łańcucha jest rzadkie, depesz stwierdza, że ​​jeden z nich jest zwykle najlepszym wyborem dla ograniczenia długości.


58
@axiopisty To świetny artykuł. Możesz po prostu powiedzieć: „Czy mógłbyś wyciągnąć kilka fragmentów na wypadek, gdyby artykuł kiedykolwiek upadł?” Próbowałem krótko streścić treść / wnioski tego artykułu. Mam nadzieję, że to wystarczy, aby złagodzić twoje obawy.
jpmc26,

34
@axiopisty, ściśle mówiąc, początkowa odpowiedź brzmiała: „ pod maską to wszystko varlena ”, co z pewnością jest użyteczną informacją, która odróżnia tę odpowiedź od odpowiedzi tylko linkiem.
Bruno,

24
Jedną z rzeczy, o których należy pamiętać przy nieograniczonym ciągu, jest to, że otwierają one możliwość nadużyć. Jeśli zezwalasz użytkownikowi na posiadanie nazwiska o dowolnym rozmiarze, być może ktoś przechowuje DUŻE ilości informacji w polu Twojego nazwiska. W artykule na temat rozwoju reddit radzą: „Ogranicz wszystko”.
Mark Hildreth,

7
@MarkHildreth Dobra uwaga, choć ogólne ograniczenia są obecnie egzekwowane w aplikacji - aby interfejs (i próby naruszeń / ponownych prób) mogły być płynnie obsługiwane przez interfejs użytkownika. Jeśli ktoś nadal chce robić coś takiego w bazie danych, może zastosować ograniczenia. Zobacz blog.jonanin.com/2013/11/20/postgresql-char-varchar, który zawiera „przykład użycia TEKSTU i ograniczeń do tworzenia pól z większą elastycznością niż VARCHAR”.
Ethan,

4
@Ethan blog.jonanin.com/2013/11/20/postgresql-char-varchar -> To nie działa, ale znaleziono tutaj archive.is/6xhA5 .
MrR

115

Jako „ zestaw znaków ” w punktach dokumentacja określająca, varchar(n), char(n), i textsą przechowywane w ten sam sposób. Jedyna różnica polega na tym, że potrzebne są dodatkowe cykle, aby sprawdzić długość, jeśli jest podana, oraz dodatkowa przestrzeń i czas wymagany, jeśli konieczne jest wypełnienie char(n).

Jednak gdy potrzebujesz zapisać tylko jeden znak, użycie specjalnego typu ma niewielką przewagę wydajności "char"(zachowaj podwójne cudzysłowy - są one częścią nazwy typu). Uzyskujesz szybszy dostęp do pola i nie ma narzutu do przechowywania długości.

Właśnie stworzyłem tabelę z losową liczbą 1 000 000 "char"wybraną z małego alfabetu. Zapytanie w celu uzyskania rozkładu częstotliwości ( select count(*), field ... group by field) zajmuje około 650 milisekund, w porównaniu z około 760 dla tych samych danych przy użyciu textpola.


18
technicznie cytaty nie są częścią nazwy typu. są potrzebne do odróżnienia go od słowa kluczowego char.
Jasen

31
Technicznie masz rację @Jasen ... Co oczywiście jest najlepszym rodzajem poprawności
JohannesH

typ danych "char" nie jest char?? Jest aktualny w PostgreSQL 11+? ... Tak: „Typ "char"(zwróć uwagę na cudzysłów) różni się od char (1) tym, że wykorzystuje tylko jeden bajt pamięci. Jest używany wewnętrznie w katalogach systemowych jako uproszczony typ wyliczenia ”. , przewodnik / znak typu danych .
Peter Krauss,

63

AKTUALIZACJA PORÓWNAWCZYCH NA 2016 R. (str.5.5 +)

I przy użyciu testów porównawczych „czystego SQL” (bez zewnętrznego skryptu)

  1. użyj dowolnego string_generatora z UTF8

  2. główne punkty odniesienia:

    2.1 WSTAWIĆ

    2.2 WYBIERZ porównywanie i liczenie


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;

Przygotuj konkretny test (przykłady)

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) );

Wykonaj podstawowy test:

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

I inne testy,

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;

... i użyj EXPLAIN ANALYZE.

AKTUALIZACJA PONOWNIE 2018 (str.10)

mała edycja, aby dodać wyniki z 2018 roku i wzmocnić rekomendacje.


Wyniki w 2016 i 2018 r

Moje wyniki, po uśrednieniu, na wielu maszynach i wielu testach: wszystkie takie same
(statystycznie mniejsze odchylenie standardowe).

Rekomendacje

  • Użyj texttypu danych,
    unikaj starych, varchar(x)ponieważ czasami nie jest to standard, np. W CREATE FUNCTIONklauzulach varchar(x)varchar(y) .

  • wyraźne limity (z tą samą varcharwydajnością!) za pomocą CHECKklauzuli CREATE TABLE
    np CHECK(char_length(x)<=10).
    Przy nieznacznej utracie wydajności w INSERT / UPDATE można także kontrolować zakresy i strukturę łańcuchów,
    npCHECK(char_length(x)>5 AND char_length(x)<=20 AND x LIKE 'Hello%')


Czy to nie ma znaczenia, że ​​wszystkie moje kolumny zmieniono na varchar zamiast tekstu? Nie podałem długości, chociaż niektóre mają tylko 4-5 znaków, a na pewno nie 255.
Wykop

1
@wykop tak, to nie ma znaczenia
FuriousFolder

1
fajnie, przerobiłem to na bezpieczne i i tak napisałem wszystko. Działało dobrze i bardzo łatwo było szybko dodać miliony historycznych zapisów.
wykop

@trench and reader: jedynym wyjątkiem jest szybszy typ danych "char", który nie jest dostępny char, nawet w dzisiejszych czasach PostgreSQL 11+. Jak mówi znak przewodnika / typu danych „Typ "char"(zwróć uwagę na cudzysłów) różni się od char (1) tym, że wykorzystuje tylko jeden bajt pamięci. Jest używany wewnętrznie w katalogach systemowych jako uproszczony typ wyliczenia ”. .
Peter Krauss,

3
nadal obowiązuje z pg11 w 2019 r .: tekst> varchar (n)> text_check> char (n)
Olivier Refalo

37

Na instrukcji PostgreSQL

Nie ma różnicy w wydajności między tymi trzema typami, oprócz zwiększonego miejsca do przechowywania przy użyciu pustego wypełnienia i kilku dodatkowych cykli procesora, aby sprawdzić długość podczas przechowywania w kolumnie o ograniczonej długości. Chociaż znak (n) ma przewagę wydajności w niektórych innych systemach baz danych, nie ma takiej przewagi w PostgreSQL; w rzeczywistości znak (n) jest zwykle najwolniejszy z trzech ze względu na dodatkowe koszty przechowywania. W większości sytuacji zamiast tego należy używać tekstu lub różnych znaków.

Zwykle używam tekstu

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


23

Moim zdaniem varchar(n)ma swoje zalety. Tak, wszystkie używają tego samego typu podstawowego i tak dalej. Należy jednak zauważyć, że indeksy w PostgreSQL mają limit wielkości 2712 bajtów na wiersz.

TL; DR: Jeśli używasz texttyp bez ograniczeń i mają indeksy na te kolumny, to jest bardzo prawdopodobne, że trafisz ten limit dla niektórych swoich kolumn i dostać błąd podczas próby wstawienia danych, ale z użyciemvarchar(n) , można temu zapobiec.

Kilka dodatkowych szczegółów: Problem polega na tym, że PostgreSQL nie podaje żadnych wyjątków podczas tworzenia indeksów dla texttypu lub varchar(n)gdzie njest większy niż 2712. Jednak da błąd, gdy spróbuje się wstawić rekord o skompresowanym rozmiarze większym niż 2712. Oznacza to, że możesz łatwo wstawić 100 000 znaków ciągu złożonego z powtarzalnych znaków, ponieważ będzie on skompresowany znacznie poniżej 2712 znaków, ale możesz nie być w stanie wstawić łańcucha zawierającego 4000 znaków, ponieważ rozmiar skompresowanego pliku jest większy niż 2712 bajtów. Używając varchar(n)gdzie nnie jest dużo większy niż 2712, jesteś bezpieczny przed tymi błędami.


Późniejsze błędy postgres przy próbie utworzenia indeksowania tekstu działają tylko dla varchar (wersja bez (n)). Testowane tylko z osadzonymi postgresami.
arntg

2
Odnosząc się do: stackoverflow.com/questions/39965834/…, który zawiera link do PostgreSQL Wiki: wiki.postgresql.org/wiki/... ma maksymalny rozmiar wiersza wynoszący 400 GB , ponieważ wygląda na to, że podany limit 2712 bajtów na wiersz jest nieprawidłowy . Maksymalny rozmiar bazy danych? nieograniczony (istnieją bazy danych 32 TB) Maksymalny rozmiar tabeli? 32 TB Maksymalny rozmiar rzędu? 400 GB Maksymalny rozmiar pola? 1 GB Maksymalna liczba wierszy w tabeli? nieograniczony
Bill Worthington,

@BillWorthington Opublikowane liczby nie uwzględniają jednak umieszczania indeksów. 2712 bajtów dotyczy maksymalnych limitów btree, jest to szczegół implementacji, więc nie można go znaleźć w dokumentach. Możesz go jednak łatwo przetestować samodzielnie lub po prostu google, wyszukując „rozmiar wiersza indeksu postgresql przekracza indeks 2712”, np.
sotn

Jestem nowy w PostgeSQL, więc nie jestem ekspertem. Pracuję nad projektem, w którym chcę przechowywać artykuły z wiadomościami w kolumnie w tabeli. Wygląda na to, że użyję typu kolumny tekstu. Łączny rozmiar wiersza 2712 bajtów wydaje się zbyt niski dla bazy danych, która powinna znajdować się na tym samym poziomie co Oracle. Czy dobrze rozumiem, że masz na myśli indeksowanie dużego pola tekstowego? Nie próbować kwestionować ani kłócić się z tobą, po prostu próbować zrozumieć prawdziwe ograniczenia. Jeśli nie ma żadnych indeksów, to czy limit wierszy wynosiłby 400 GB, jak na wiki? Dziękuję za szybką odpowiedź.
Bill Worthington,

1
@BillWorthington Powinieneś dowiedzieć się więcej o wyszukiwaniu pełnotekstowym. Sprawdź ten link, np.
sotn

18

tekst i varchar mają różne niejawne konwersje typów. Największy wpływ, jaki zauważyłem, to obsługa spacji końcowych. Na przykład ...

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

zwraca, true, false, truea nie true, true, truejak można się spodziewać.


Jak to jest możliwe? Jeśli a = bi a = c, to b = c.
Lucas Silva

4

Nieco OT: jeśli używasz Railsów, standardowe formatowanie stron internetowych może być inne. W przypadku formularzy do wprowadzania danych textpola można przewijać, ale pola character varying(Szyny string) są jednowierszowe. Pokaż widoki są tak długo, jak to konieczne.


2

Dobre wyjaśnienie z http://www.sqlines.com/postgresql/datatypes/text :

Jedyną różnicą między TEKSTEM a VARCHAR (n) jest to, że można ograniczyć maksymalną długość kolumny VARCHAR, na przykład VARCHAR (255) nie pozwala na wstawianie ciągu dłuższego niż 255 znaków.

Zarówno TEKST, jak i VARCHAR mają górny limit na 1 Gb i nie ma między nimi żadnej różnicy w wydajności (zgodnie z dokumentacją PostgreSQL).


-1

character varying(n), varchar(n)- (Oba te same). wartość zostanie obcięta do n znaków bez zgłaszania błędu.

character(n), char(n)- (Oba te same). o stałej długości i będzie podkładał puste miejsca do końca długości.

text- Nieograniczona długość.

Przykład:

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

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

Otrzymujemy wyniki:

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

5
Podczas gdy MySQL po cichu obetnie dane, gdy wartość przekroczy rozmiar kolumny, PostgreSQL nie będzie i podniesie błąd „zbyt długa dla błędu zmiany znaku typu (n)”.
gsiems
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.