PostgreSQL: Diferença entre texto e varchar (variação de caracteres)


620

Qual é a diferença entre o texttipo de dados e os tipos de dados character varying( varchar)?

De acordo com a documentação

Se a variação de caracteres for usada sem o especificador de comprimento, o tipo aceitará seqüências de caracteres de qualquer tamanho. Este último é uma extensão do PostgreSQL.

e

Além disso, o PostgreSQL fornece o tipo de texto, que armazena seqüências de caracteres de qualquer tamanho. Embora o texto do tipo não esteja no padrão SQL, vários outros sistemas de gerenciamento de banco de dados SQL também o possuem.

Então qual a diferença?

Respostas:


746

Não há diferença, por baixo do capô é tudo varlena( matriz de comprimento variável ).

Verifique este artigo da Depesz: http://www.depesz.com/index.php/2010/03/02/charx-vs-varcharx-vs-varchar-vs-text/

Alguns destaques:

Para resumir tudo:

  • char (n) - ocupa muito espaço ao lidar com valores menores que n(preenche-os n) e pode levar a erros sutis devido à adição de espaços finais, além de ser problemático alterar o limite
  • varchar (n) - é problemático alterar o limite no ambiente ativo (requer bloqueio exclusivo ao alterar a tabela)
  • varchar - assim como o texto
  • texto - para mim um vencedor - sobre (n) tipos de dados porque não possui problemas e sobre varchar - porque possui um nome distinto

O artigo faz testes detalhados para mostrar que o desempenho das inserções e seleções para todos os quatro tipos de dados é semelhante. Ele também analisa detalhadamente maneiras alternativas de restringir o comprimento quando necessário. Restrições ou domínios baseados em funções fornecem a vantagem do aumento instantâneo da restrição de comprimento e, com base no fato de que diminuir uma restrição de comprimento de sequência é raro, depesz conclui que uma delas geralmente é a melhor opção para um limite de comprimento.


58
@axiopisty É um ótimo artigo. Você poderia apenas dizer: "Você poderia extrair alguns trechos para o caso de o artigo ser publicado?" Tentei resumir brevemente o conteúdo / conclusões do artigo. Espero que isso seja suficiente para facilitar suas preocupações.
jpmc26

34
@axiopisty, estritamente falando, a resposta inicial foi dizer " sob o capô é tudo varlena ", que certamente é uma informação útil que distingue essa resposta de uma resposta somente de link.
Bruno

24
Uma coisa a ter em mente com uma corda ilimitada é que elas abrem o potencial de abuso. Se você permitir que um usuário tenha um sobrenome de qualquer tamanho, pode ser que alguém armazene grandes quantidades de informações em seu campo de sobrenome. Em um artigo sobre o desenvolvimento do reddit, eles dão conselhos para "colocar um limite em tudo".
Mark Hildreth

7
@MarkHildreth Bom ponto, apesar de geralmente restrições como essa serem aplicadas mais adiante em um aplicativo hoje em dia - para que as regras (e tentativas de violação / nova tentativa) possam ser tratadas sem problemas pela interface do usuário. Se alguém ainda quiser fazer esse tipo de coisa no banco de dados, poderá usar restrições. Consulte blog.jonanin.com/2013/11/20/postgresql-char-varchar, que inclui "um exemplo de uso de TEXT e restrições para criar campos com mais flexibilidade que o VARCHAR".
Ethan

4
@Ethan blog.jonanin.com/2013/11/20/postgresql-char-varchar -> Está desativado, mas foi encontrado aqui archive.is/6xhA5 .
MrRodrigues18

115

Como " tipos de caracteres " nos pontos de documentação para fora, varchar(n), char(n), e textsão armazenados da mesma maneira. A única diferença é que são necessários ciclos extras para verificar o comprimento, se houver, e o espaço e tempo extras necessários para o preenchimento char(n).

No entanto, quando você só precisa armazenar um único caractere, há uma pequena vantagem de desempenho em usar o tipo especial "char"(mantenha as aspas duplas - elas fazem parte do nome do tipo). Você obtém acesso mais rápido ao campo e não há sobrecarga para armazenar o comprimento.

Acabei de criar uma tabela de 1.000.000 de caracteres aleatórios "char"escolhidos no alfabeto minúsculo. Uma consulta para obter uma distribuição de frequência ( select count(*), field ... group by field) leva cerca de 650 milissegundos, contra cerca de 760 nos mesmos dados usando um textcampo.


18
tecnicamente, as aspas não fazem parte do nome do tipo. eles são necessários para diferenciá-lo da palavra-chave char.
Jasen

31
Tecnicamente você está correto @Jasen ... O que, claro, é o melhor tipo de correta
JohannesH

tipo de dados "char" não é char?? Atualmente é válido no PostgreSQL 11+? ... Sim: "O tipo "char"(observe as aspas) é diferente de char (1), pois usa apenas um byte de armazenamento. Ele é usado internamente nos catálogos do sistema como um tipo de enumeração simplista ." , guia / tipo de dados caractere .
Peter Krauss

64

ATUALIZAÇÃO DE BENCHMARKS PARA 2016 (pág. 9.5 +)

E usando benchmarks "puro SQL" (sem nenhum script externo)

  1. use qualquer string_generator com UTF8

  2. principais benchmarks:

    2.1 INSERIR

    2.2 SELECIONAR comparando e contando


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;

Preparar teste específico (exemplos)

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

Execute um teste básico:

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

E outros testes,

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 use EXPLAIN ANALYZE.

ATUALIZADO NOVAMENTE 2018 (página 10)

pouca edição para adicionar os resultados de 2018 e reforçar as recomendações.


Resultados em 2016 e 2018

Meus resultados, depois da média, em muitas máquinas e muitos testes: todos iguais
(estatisticamente menos do que o desvio padrão).

Recomendação

  • Use o texttipo de dados,
    evite o antigo, varchar(x)porque às vezes não é um padrão, por exemplo, nas CREATE FUNCTIONcláusulas varchar(x)varchar(y) .

  • expressar limites (com o mesmo varchardesempenho!) por com CHECKcláusula no CREATE TABLE
    eg CHECK(char_length(x)<=10).
    Com uma perda insignificante de desempenho em INSERT / UPDATE, você também pode controlar intervalos e estrutura de cadeias,
    por exemploCHECK(char_length(x)>5 AND char_length(x)<=20 AND x LIKE 'Hello%')


Portanto, não importa que eu tenha feito todas as minhas colunas varchar em vez de texto? Eu não especifiquei o tamanho, embora alguns tenham apenas 4-5 caracteres e certamente não 255. #
trench

1
@trench sim, não importa
FuriousFolder

1
legal, refizi-o para ser seguro e fiz todo o texto de qualquer maneira. Funcionou bem e foi super fácil adicionar milhões de registros históricos rapidamente de qualquer maneira.
trincheira

@ trench e reader: a única exceção é o tipo de dados mais rápido "char", que não é char, mesmo nos dias atuais do PostgreSQL 11+. Como o caractere de guia / tipo de dados diz "O tipo "char"(observe as aspas) é diferente de char (1), pois usa apenas um byte de armazenamento. Ele é usado internamente nos catálogos do sistema como um tipo de enumeração simplista ". .
Peter Krauss

3
ainda válido com pg11 em 2019: text> varchar (n)> text_check> char (n)
Olivier Refalo 08/02/19

37

No manual do PostgreSQL

Não há diferença de desempenho entre esses três tipos, além do aumento do espaço de armazenamento ao usar o tipo preenchido em branco e alguns ciclos extras de CPU para verificar o comprimento ao armazenar em uma coluna com restrição de comprimento. Embora o caractere (n) tenha vantagens de desempenho em alguns outros sistemas de banco de dados, não existe essa vantagem no PostgreSQL; de fato, o caractere (n) geralmente é o mais lento dos três devido aos seus custos adicionais de armazenamento. Na maioria das situações, a variação de texto ou caractere deve ser usada.

Eu costumo usar texto

Referências: http://www.postgresql.org/docs/current/static/datatype-character.html


23

Na minha opinião, varchar(n)tem suas próprias vantagens. Sim, todos eles usam o mesmo tipo subjacente e tudo isso. Porém, deve-se ressaltar que os índices no PostgreSQL têm seu limite de tamanho de 2712 bytes por linha.

TL; DR: Se você usar o texttipo sem restrição e tiver índices nessas colunas, é muito possível que você atinja esse limite para algumas de suas colunas e receba um erro ao tentar inserir dados, mas com o uso varchar(n), poderá evitá-lo.

Mais alguns detalhes: O problema aqui é que o PostgreSQL não oferece nenhuma exceção ao criar índices para o texttipo ou varchar(n)onde né maior que 2712. No entanto, ocorrerá um erro ao tentar inserir um registro com tamanho compactado maior que 2712. Isso significa que você pode inserir 100.000 caracteres da sequência, que é composta por caracteres repetitivos facilmente, porque será compactada muito abaixo de 2712, mas talvez não seja possível inserir uma sequência com 4000 caracteres, porque o tamanho compactado é maior que 2712 bytes. Usando varchar(n)onde nnão é muito maior que 2712, você está seguro contra esses erros.


Os erros posteriores do postgres ao tentar criar indexação para texto funcionam apenas para varchar (versão sem o (n)). Apenas testado com postgres incorporados.
Arntg 07/11

2
Referindo-se a: stackoverflow.com/questions/39965834/… que possui um link para o PostgreSQL Wiki: wiki.postgresql.org/wiki/… tem tamanho máximo de linha de 400 GB , pelo que parece que o limite de 2712 bytes por linha está incorreto . Tamanho máximo para um banco de dados? ilimitado (existem bancos de dados de 32 TB) Tamanho máximo para uma tabela? 32 TB Tamanho máximo para uma linha? 400 GB Tamanho máximo para um campo? 1 GB Número máximo de linhas em uma tabela? ilimitado
Bill Worthington

@ BillWorthington Os números que você postou não levam em consideração a colocação de índices. 2712 bytes refere-se aos limites máximos da btree, é um detalhe de implementação para que você não possa encontrá-lo nos documentos. No entanto, você pode testá-lo facilmente ou apenas pesquisá-lo no Google pesquisando "o tamanho da linha de índice do postgresql excede o máximo de 2712 para o índice", por exemplo.
SOTN

Eu sou novo no PostgeSQL, então não sou o especialista. Estou trabalhando em um projeto em que quero armazenar artigos de notícias em uma coluna em uma tabela. Parece que o tipo de coluna de texto é o que vou usar. Um tamanho total de linha de 2712 bytes parece muito baixo para um banco de dados que se supõe estar próximo do mesmo nível que o Oracle. Entendi corretamente que você está se referindo à indexação de um campo de texto grande? Não tentando desafiar ou discutir com você, apenas tentando entender os limites reais. Se não houver índices envolvidos, o limite de linhas seria de 400 GB, como no wiki? Obrigado pela sua resposta rápida.
Bill Worthington

1
@ BillWorthington Você deve pesquisar sobre a Pesquisa de texto completo. Verifique este link, por exemplo,
sotn

18

text e varchar têm diferentes conversões implícitas de tipo. O maior impacto que notei é a manipulação de espaços à direita. Por exemplo ...

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

retorna true, false, truee não true, true, truecomo você poderia esperar.


Como isso é possível? Se a = b e a = c, então b = c.
Lucas Silva

4

Um pouco OT: se você estiver usando o Rails, a formatação padrão das páginas da web pode ser diferente. Para formulários de entrada de dados, as textcaixas podem ser roladas, mas as caixas character varying(Rails string) são de uma linha. As exibições de exibição duram o necessário.


2

Uma boa explicação de http://www.sqlines.com/postgresql/datatypes/text :

A única diferença entre TEXT e VARCHAR (n) é que você pode limitar o comprimento máximo de uma coluna VARCHAR, por exemplo, VARCHAR (255) não permite inserir uma sequência com mais de 255 caracteres.

Tanto o TEXT quanto o VARCHAR têm o limite superior de 1 Gb e não há diferença de desempenho entre eles (de acordo com a documentação do PostgreSQL).


-1

character varying(n), varchar(n)- (Ambos iguais). o valor será truncado para n caracteres sem gerar um erro.

character(n), char(n)- (Ambos iguais). comprimento fixo e preenchido com espaços em branco até o final do comprimento.

text- comprimento ilimitado.

Exemplo:

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

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

Nós obtemos os resultados:

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

5
Enquanto o MySQL silenciosamente truncará os dados quando o valor exceder o tamanho da coluna, o PostgreSQL não aumentará e aumentará um erro "valor muito longo para o tipo de variação de caracteres (n)".
gsiems
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.