PostgreSQL: Differenza tra testo e varchar (carattere variabile)


620

Qual è la differenza tra il texttipo di dati e i tipi di dati character varying( varchar)?

Secondo la documentazione

Se si utilizza la variazione di carattere senza identificatore di lunghezza, il tipo accetta stringhe di qualsiasi dimensione. Quest'ultima è un'estensione PostgreSQL.

e

Inoltre, PostgreSQL fornisce il tipo di testo, che memorizza stringhe di qualsiasi lunghezza. Sebbene il testo del tipo non sia nello standard SQL, anche molti altri sistemi di gestione del database SQL lo hanno.

Quindi qual è la differenza?

Risposte:


746

Non c'è differenza, sotto il cofano è tutto varlena( array di lunghezza variabile ).

Controlla questo articolo da Depesz: http://www.depesz.com/index.php/2010/03/02/charx-vs-varcharx-vs-varchar-vs-text/

Un paio di punti salienti:

Per riassumere tutto:

  • char (n) - occupa troppo spazio quando si ha a che fare con valori più brevi di n(li riempie in n) e può portare a sottili errori a causa dell'aggiunta di spazi finali, inoltre è problematico modificare il limite
  • varchar (n) - è problematico modificare il limite nell'ambiente live (richiede un blocco esclusivo durante la modifica della tabella)
  • varchar: proprio come il testo
  • testo - per me un vincitore - su (n) tipi di dati perché manca di problemi e su varchar - perché ha un nome distinto

L'articolo esegue test dettagliati per dimostrare che le prestazioni degli inserti e delle selezioni per tutti e 4 i tipi di dati sono simili. Dà anche un'occhiata dettagliata a modi alternativi per limitare la lunghezza quando necessario. I vincoli o i domini basati su funzioni offrono il vantaggio di un aumento istantaneo del vincolo di lunghezza e sulla base del fatto che la riduzione di un vincolo di lunghezza della stringa è rara, depesz conclude che uno di essi è di solito la scelta migliore per un limite di lunghezza.


58
@axiopisty È un ottimo articolo. Potresti semplicemente dire: "Potresti inserire alcuni estratti nel caso in cui l'articolo dovesse mai scendere?" Ho provato a sintetizzare brevemente il contenuto / le conclusioni dell'articolo. Spero che questo sia abbastanza per alleviare le tue preoccupazioni.
jpmc26

34
@axiopisty, a rigor di termini, la risposta iniziale stava dicendo " sotto il cofano è tutto varlena ", che è certamente un'informazione utile che distingue questa risposta da una risposta solo link.
Bruno,

24
Una cosa da tenere a mente con una stringa senza limiti è che aprono il potenziale di abuso. Se si consente a un utente di avere un cognome di qualsiasi dimensione, è possibile che qualcuno memorizzi GRANDI quantità di informazioni nel campo del cognome. In un articolo sullo sviluppo di reddit, danno il consiglio di "Mettere un limite a tutto".
Mark Hildreth,

7
@MarkHildreth Un buon punto, anche se in questi giorni i vincoli di questo tipo vengono applicati più avanti in un'applicazione, in modo che le regole (e i tentativi di violazioni / tentativi) possano essere gestite senza problemi dall'IU. Se qualcuno vuole ancora fare questo genere di cose nel database, potrebbe usare i vincoli. Vedi blog.jonanin.com/2013/11/20/postgresql-char-varchar che include "un esempio di utilizzo di TEXT e vincoli per creare campi con maggiore flessibilità rispetto a VARCHAR".
Ethan,

4
@Ethan blog.jonanin.com/2013/11/20/postgresql-char-varchar -> Non funziona, ma è disponibile qui archive.is/6xhA5 .
MrR

115

Come " Tipi di carattere " nei punti di documentazione fuori, varchar(n), char(n), e textsono tutti memorizzati nello stesso modo. L'unica differenza è che sono necessari cicli extra per controllare la lunghezza, se ne viene data una, e lo spazio e il tempo extra necessari se è necessaria l'imbottitura char(n).

Tuttavia, quando devi solo memorizzare un singolo carattere, c'è un leggero vantaggio prestazionale nell'usare il tipo speciale "char"(mantieni le virgolette doppie - fanno parte del nome del tipo). Ottieni un accesso più veloce al campo e non c'è un overhead per memorizzare la lunghezza.

Ho appena creato una tabella di 1.000.000 di casuali "char"scelti dall'alfabeto minuscolo. Una query per ottenere una distribuzione di frequenza ( select count(*), field ... group by field) richiede circa 650 millisecondi, contro circa 760 sugli stessi dati utilizzando un textcampo.


18
tecnicamente le virgolette non fanno parte del nome del tipo. sono necessari per differenziarlo dalla parola chiave char.
Jasen,

31
Tecnicamente hai ragione @Jasen ... Che, ovviamente, è il miglior tipo di correzione
JohannesH,

tipo di dati "char" non è char?? È valido al giorno d'oggi di PostgreSQL 11+? ... Sì: "Il tipo "char"(notare le virgolette) è diverso da char (1) in quanto utilizza solo un byte di memoria. È utilizzato internamente nei cataloghi di sistema come tipo di enumerazione semplicistico ." , carattere guida / tipo di dati .
Peter Krauss,

64

AGGIORNAMENTO DEI BENCHMARKS PER IL 2016 (pag. 9.5 +)

E usando benchmark "pure SQL" (senza alcuno script esterno)

  1. usa qualsiasi string_generator con UTF8

  2. parametri di riferimento principali:

    2.1. INSERIRE

    2.2. SELEZIONA il confronto e il conteggio


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;

Preparare test specifici (esempi)

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

Eseguire un test di base:

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

E altri test,

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;

... E usa EXPLAIN ANALYZE.

AGGIORNATO ANCORA 2018 (pg10)

piccola modifica per aggiungere i risultati del 2018 e rafforzare i consigli.


Risultati nel 2016 e 2018

I miei risultati, dopo la media, in molte macchine e in molti test: tutti uguali
(deviazione standard statisticamente inferiore al tham).

Raccomandazione

  • Usa il texttipo di dati,
    evita i vecchi varchar(x)perché a volte non è uno standard, ad esempio nelle CREATE FUNCTIONclausole varchar(x)varchar(y) .

  • esprimere limiti (con le stesse varcharprestazioni!) di con CHECKclausola CREATE TABLE
    nell'es CHECK(char_length(x)<=10).
    Con una perdita trascurabile di prestazioni in INSERT / UPDATE è anche possibile controllare intervalli e struttura delle stringhe
    ad esCHECK(char_length(x)>5 AND char_length(x)<=20 AND x LIKE 'Hello%')


Quindi non importa che ho fatto varchar tutte le mie colonne invece del testo? Non ho specificato la lunghezza anche se alcuni sono solo 4 - 5 caratteri e certamente non 255.
trincea

1
@trench sì, non importa
FuriousFolder

1
bello, l'ho rifatto per essere sicuro e ho fatto comunque tutto il testo. Ha funzionato bene ed è stato semplicissimo aggiungere rapidamente milioni di record storici in ogni caso.
trincea,

@trench e lettore: l'unica eccezione è il tipo di dati più veloce "char", che non lo è char, anche ai giorni nostri di PostgreSQL 11+. Come dice il carattere guida / tipo di dati "Il tipo "char"(notare le virgolette) è diverso da char (1) in quanto utilizza solo un byte di memoria. È utilizzato internamente nei cataloghi di sistema come un tipo di enumerazione semplicistico ." .
Peter Krauss,

3
ancora valido con pg11 nel 2019: testo> varchar (n)> text_check> char (n)
Olivier Refalo

37

Sul manuale PostgreSQL

Non vi è alcuna differenza di prestazioni tra questi tre tipi, a parte un maggiore spazio di archiviazione quando si utilizza il tipo con riempimento vuoto e alcuni cicli CPU aggiuntivi per controllare la lunghezza durante l'archiviazione in una colonna con vincoli di lunghezza. Sebbene il carattere (n) presenti vantaggi in termini di prestazioni in alcuni altri sistemi di database, PostgreSQL non offre tali vantaggi; infatti il ​​carattere (n) è di solito il più lento dei tre a causa dei suoi costi di archiviazione aggiuntivi. Nella maggior parte dei casi, invece, è necessario utilizzare testo o caratteri diversi.

Di solito uso il testo

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


23

Secondo me, varchar(n)ha i suoi vantaggi. Sì, usano tutti lo stesso tipo di base e tutto il resto. Tuttavia, va sottolineato che gli indici in PostgreSQL hanno un limite di dimensione di 2712 byte per riga.

TL; DR: se si utilizza il texttipo senza un vincolo e si hanno indici su queste colonne, è molto probabile che si raggiunga questo limite per alcune delle colonne e si ottenga un errore quando si tenta di inserire dati ma con l'utilizzo varchar(n), è possibile impedirlo.

Alcuni ulteriori dettagli: Il problema qui è che PostgreSQL non dà alcuna eccezione durante la creazione di indici per il texttipo o varchar(n)dove nè maggiore di 2712. Tuttavia, darà errore quando si tenta di inserire un record con dimensioni compresse superiori a 2712. Significa che puoi inserire facilmente 100.000 caratteri di stringa che sono composti da caratteri ripetitivi perché saranno compressi molto al di sotto di 2712 ma potresti non essere in grado di inserire una stringa con 4000 caratteri perché la dimensione compressa è maggiore di 2712 byte. Usando varchar(n)dove nnon è troppo grande di 2712, sei al sicuro da questi errori.


In seguito gli errori di postgres nel tentativo di creare l'indicizzazione per il testo funzionano solo per varchar (versione senza la (n)). Testato solo con Postgres incorporato.
arntg

2
Facendo riferimento a: stackoverflow.com/questions/39965834/... che ha un collegamento a PostgreSQL Wiki: wiki.postgresql.org/wiki/... ha dimensioni Row massimo come 400GB, da che sembra che il 2712 limite di byte dichiarato per riga è sbagliata . Dimensione massima per un database? illimitato (esistono database da 32 TB) Dimensione massima per una tabella? 32 TB Dimensione massima per una riga? 400 GB Dimensione massima per un campo? 1 GB Numero massimo di righe in una tabella? illimitato
Bill Worthington,

@BillWorthington I numeri che hai pubblicato non tengono conto del fatto di mettere gli indici. 2712 byte riguarda i limiti massimi di btree, è un dettaglio di implementazione in modo che non sia possibile trovarlo nei documenti. Tuttavia, puoi facilmente testarlo da solo o cercarlo su Google cercando "la dimensione dell'indice postgresql supera il massimo 2712 per l'indice" ad es.
Sotn,

Sono nuovo di PostgeSQL, quindi non sono un esperto. Sto lavorando a un progetto in cui desidero archiviare articoli di notizie in una colonna di una tabella. Sembra che il tipo di colonna di testo sia quello che userò. Una dimensione di riga totale di 2712 byte sembra troppo bassa per un database che si suppone sia vicino allo stesso livello di Oracle. Ti capisco correttamente che ti riferisci all'indicizzazione di un campo di testo di grandi dimensioni? Non cercare di sfidare o discutere con te, solo cercare di capire i limiti reali. Se non ci sono indici coinvolti, il limite di riga sarebbe 400 GB come nel wiki ?? Grazie per la tua rapida risposta.
Bill Worthington,

1
@BillWorthington Dovresti fare ricerche sulla ricerca full-text. Controlla questo link, ad es.
sotn,

18

text e varchar hanno conversioni di tipo implicito differenti. L'impatto più grande che ho notato è la gestione degli spazi finali. Per esempio ...

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

ritorna true, false, truee non true, true, truecome ci si potrebbe aspettare.


Com'è possibile? Se a = b e a = c, allora b = c.
Lucas Silva,

4

In qualche modo OT: se stai usando Rails, la formattazione standard delle pagine web potrebbe essere diversa. Per i moduli di immissione dati, le textcaselle sono scorrevoli, ma le caselle character varying(Rotaie string) sono a riga singola. Le visualizzazioni dello spettacolo sono lunghe quanto necessario.


2

Una buona spiegazione da http://www.sqlines.com/postgresql/datatypes/text :

L'unica differenza tra TEXT e VARCHAR (n) è che è possibile limitare la lunghezza massima di una colonna VARCHAR, ad esempio VARCHAR (255) non consente l'inserimento di una stringa lunga più di 255 caratteri.

Sia TEXT che VARCHAR hanno il limite superiore a 1 Gb e non vi sono differenze di prestazioni tra loro (secondo la documentazione di PostgreSQL).


-1

character varying(n), varchar(n)- (Entrambi uguali). il valore verrà troncato a n caratteri senza generare un errore.

character(n), char(n)- (Entrambi uguali). a lunghezza fissa e riempirà con spazi vuoti fino alla fine della lunghezza.

text- Lunghezza illimitata.

Esempio:

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

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

Otteniamo i risultati:

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

5
Mentre MySQL troncerà silenziosamente i dati quando il valore supera la dimensione della colonna, PostgreSQL non genererà e genererà un errore "valore troppo lungo per il carattere che varia (n)".
gsiems
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.