Rendimento dell'indice per CHAR vs VARCHAR (Postgres)


16

In questa risposta ( /programming/517579/strings-as-primary-keys-in-sql-database ) un singolo commento ha attirato la mia attenzione:

Inoltre, tieni presente che spesso c'è una differenza molto grande tra un CHAR e un VARCHAR quando si effettuano confronti di indici

Questo vale / è ancora valido per Postgres?

Ho trovato pagine su Oracle che affermano che CHARè più o meno un alias VARCHARe quindi le prestazioni dell'indice sono le stesse, ma non ho trovato nulla di definitivo su Postgres.

Risposte:


24

CHARe VARCHARsono implementati esattamente lo stesso in Postgres (e Oracle). Non vi è alcuna differenza di velocità quando si utilizzano questi tipi di dati.

Tuttavia, esiste una differenza che può fare la differenza in termini di prestazioni: una charcolonna viene sempre riempita per la lunghezza definita. Pertanto, se si definisce una colonna come char(100)e una come, varchar(100)ma si memorizzano solo 10 caratteri in ciascuna, la char(100)colonna utilizza 100 caratteri per ciascun valore (i 10 caratteri memorizzati, più 90 spazi), mentre la varcharcolonna memorizza solo 10 caratteri.

Il confronto di 100 caratteri con 100 caratteri sarà più lento rispetto al confronto di 10 caratteri con 10 caratteri, anche se dubito che tu possa effettivamente misurare questa differenza in una query SQL.

Se dichiari entrambi con la lunghezza di 10 caratteri e li memorizzi sempre esattamente 10 caratteri, allora non c'è assolutamente alcuna differenza (questo è vero per Oracle e Postgres)

Quindi l'unica differenza è il riempimento che viene eseguito per il chartipo di dati.


Inoltre, tieni presente che spesso c'è una differenza molto grande tra un CHAR e un VARCHAR quando si effettuano confronti di indici

La citazione sopra è vera solo se (e solo se) la charcolonna è definita troppo ampia (cioè stai sprecando spazio a causa del riempimento). Se la lunghezza della charcolonna viene sempre utilizzata completamente (quindi non si verifica alcuna imbottitura), la citazione sopra è errata (almeno per Postgres e Oracle)


Dal mio punto di vista, il chartipo di dati non ha davvero alcun uso di parole reali. Usa varchar(o textin Postgres) e dimentica che charesiste.


2
Il confronto di 100 caratteri con 100 caratteri sarà più lento rispetto al confronto di 10 caratteri con 10 caratteri, anche se dubito che tu possa effettivamente misurare questa differenza in una query SQL. - A seconda di cosa fa la query oltre all'ordinamento, la differenza può essere enorme. Ecco perché Postgres 9.5 ha una nuova funzione di "chiavi abbreviate": pgeoghegan.blogspot.de/2015/01/…
chirlu,

6

Sono d'accordo con tutto quanto detto da a_horse_with_no_name e generalmente sono d'accordo con il consiglio di commento di Erwin:

No, char è inferiore (e obsoleto). text e varchar si comportano (quasi) allo stesso modo.

Metadati

Con una piccola eccezione, l' unica volta che uso char()è quando voglio che i metadati diano che DEVE avere caratteri x. Anche se so che mi char()lamento solo se l'input supera il limite, spesso proteggerò dai sottotitoli in un CHECKvincolo. Per esempio,

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

Lo faccio per alcuni motivi,

  1. char(x)viene talvolta dedotto con i caricatori di schemi come una colonna a larghezza fissa. Ciò può fare la differenza in una lingua ottimizzata per stringhe a larghezza fissa.
  2. Stabilisce una convenzione che ha senso ed è facilmente applicabile. Posso scrivere un caricatore di schemi in una lingua per generare codice da questa convenzione.

Ho bisogno di un esempio di dove posso farlo,

  1. Abbreviazioni di stato a due lettere, sebbene poiché questo elenco può essere elencato, lo farò in genere con un ENUM.
  2. Numeri di identificazione del veicolo
  3. Numeri di modello (di dimensioni fisse)

Sugli errori

Si noti che alcune persone potrebbero essere a disagio con l'incongruenza dei messaggi di errore su entrambi i lati del limite, ma non mi dà fastidio

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)

In contrasto con varchar

Inoltre, penso che il suggerimento di cui sopra si adatti molto bene a una convenzione di uso quasi sempretext . Chiedi varchar(n)anche tu . Non lo uso mai . Almeno, non ricordo l'ultima volta che ho usato varchar(n).

  • Se una specifica ha un campo a larghezza statica di cui mi fido, utilizzo char(n),
  • Altrimenti, uso quello textche è effettivamente varchar(nessun limite)

Se trovassi una specifica che avesse chiavi di testo a lunghezza variabile che fossero significative e che mi fossi fidato di avere una lunghezza massima costante, lo avrei usato varchar(n)anch'io. Tuttavia, non riesco a pensare a nulla che soddisfi questi criteri.

Note aggiuntive

Domande e risposte correlate:


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*

Oracolo

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 non si riempiva di spazi.


È solo un'illusione ottica in Postgres. ProvaSELECT pg_column_size(y) FROM x;
dezso

-2

Ho trovato questa spiegazione molto utile e veloce su 3 righe:

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

  • Se si desidera memorizzare del testo con una lunghezza sconosciuta, utilizzare il TEXTtipo di dati.
  • Se si desidera memorizzare del testo con una lunghezza sconosciuta, ma si conosce la lunghezza massima, utilizzare VARCHAR(n).
  • Se si desidera memorizzare del testo con una lunghezza esatta nota, utilizzare CHAR(N).
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.