Desempenho do índice para CHAR vs VARCHAR (Postgres)

15

Nesta resposta ( /programming/517579/strings-as-primary-keys-in-sql-database ), uma única observação chamou minha atenção:

Lembre-se também de que muitas vezes há uma grande diferença entre um CHAR e um VARCHAR ao fazer comparações de índice

Isso se aplica / ainda se aplica ao Postgres?

Encontrei páginas no Oracle afirmando que CHARé mais ou menos um alias para VARCHARe, portanto, o desempenho do índice é o mesmo, mas não encontrei nada definitivo no Postgres.

LetMeSOThat4U
fonte

Respostas:

24

CHARe VARCHARsão implementados exatamente da mesma forma no Postgres (e Oracle). Não há diferença de velocidade ao usar esses tipos de dados.

No entanto, há uma diferença que pode fazer a diferença no desempenho: uma charcoluna é sempre preenchida no comprimento definido. Portanto, se você definir uma coluna como char(100)e uma como varchar(100)armazenar apenas 10 caracteres em cada uma, a char(100)coluna usará 100 caracteres para cada valor (os 10 caracteres armazenados, mais 90 espaços), enquanto a varcharcoluna armazena apenas 10 caracteres.

Comparar 100 caracteres com 100 caracteres será mais lento do que comparar 10 caracteres com 10 caracteres - embora eu duvide que você possa realmente medir essa diferença em uma consulta SQL.

Se você declarar ambos com o comprimento de 10 caracteres e sempre armazenar exatamente 10 caracteres, não haverá absolutamente nenhuma diferença (isso é verdade para Oracle e Postgres)

Portanto, a única diferença é o preenchimento feito para o chartipo de dados.


Lembre-se também de que muitas vezes há uma grande diferença entre um CHAR e um VARCHAR ao fazer comparações de índice

A citação acima é verdadeira se (e somente se) a charcoluna estiver definida muito ampla (isto é, você está desperdiçando espaço devido ao preenchimento). Se o comprimento da charcoluna for sempre usado completamente (para que não ocorra preenchimento), a cotação acima estará errada (pelo menos para Postgres e Oracle)


Do meu ponto de vista, o chartipo de dados realmente não tem uso de palavras reais. Basta usar varchar(ou textno Postgres) e esquecer que charexiste.

um cavalo sem nome
fonte
2
Comparar 100 caracteres com 100 caracteres será mais lento do que comparar 10 caracteres com 10 caracteres - embora eu duvide que você possa realmente medir essa diferença em uma consulta SQL. - Dependendo do que a consulta faz, além da classificação, a diferença pode ser enorme. É por isso que o Postgres 9.5 possui um novo recurso de "chaves abreviadas": pgeoghegan.blogspot.de/2015/01/…
chirlu
6

Concordo com tudo o que foi dito por a_horse_with_no_name, e geralmente concordo com os conselhos de comentários de Erwin:

Não, char é inferior (e desatualizado). text e varchar executam (quase) o mesmo.

Metadados

Com uma pequena exceção, a única vez que uso char()é quando quero que os metadados digam que DEVE ter caracteres x. Embora eu saiba que char()apenas reclame se a entrada estiver acima do limite, frequentemente protegerei contra subidas devido a uma CHECKrestrição. Por exemplo,

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

Eu faço isso por alguns motivos,

  1. char(x)às vezes é inferido com carregadores de esquema como sendo uma coluna de largura fixa. Isso pode fazer a diferença em um idioma otimizado para cadeias de largura fixa.
  2. Estabelece uma convenção que faz sentido e é facilmente aplicada. Eu posso escrever um carregador de esquema em um idioma para gerar código a partir desta convenção.

Preciso de um exemplo de onde eu possa fazer isso,

  1. Abreviações de estado de duas letras, embora, como essa lista possa ser enumerada, eu normalmente o faça com um ENUM.
  2. Números de identificação do veículo
  3. Números de modelo (de tamanho fixo)

Sobre erros

Observe que algumas pessoas podem se sentir desconfortáveis ​​com a incongruência das mensagens de erro nos dois lados do limite, mas isso não me incomoda

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)

Contraste com varchar

Além disso, acho que a sugestão acima se encaixa muito bem com uma convenção de quase sempre usotext . Você pergunta sobre varchar(n)também. Eu nunca uso isso . Pelo menos, não me lembro da última vez que usei varchar(n).

  • Se uma especificação tem um campo de largura estática em que eu confio, eu uso char(n),
  • Caso contrário, eu uso o textque é efetivamente varchar(sem limite)

Se eu encontrasse uma especificação que tivesse chaves de texto de comprimento variável que fossem significativas e que eu confiasse em ter um comprimento máximo constante, eu usaria varchar(n) também . No entanto, não consigo pensar em nada que se encaixe nesse critério.

Notas Adicionais

Perguntas e Respostas relacionadas:

Evan Carroll
fonte
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*

Oráculo

SQL> create table x ( y char(2));

Table created.

SQL> insert into x values ('Y');

1 row created.

SQL> select '*' || y || '*' from x;

'*'|
----
*Y *

O Postgresql não preenchia com espaços.

user939857
fonte
Isso é apenas uma ilusão de ótica no Postgres. TenteSELECT pg_column_size(y) FROM x;
dezso
-2

Achei isso mais útil e uma explicação rápida de 3 linhas:

De CHAR (n) Vs VARCHAR (N) Vs texto no Postgres

  • Se você deseja armazenar algum texto com um comprimento desconhecido, use o TEXTtipo de dados.
  • Se você deseja armazenar algum texto com um comprimento desconhecido, mas você sabe o tamanho máximo, use VARCHAR(n).
  • Se você deseja armazenar algum texto com um comprimento exato conhecido, use CHAR(N).
Lewis
fonte