VARCHAR2 vs CHAR: Diferenças que Impactam Desempenho e Armazenamento

Aproveitei um tema recorrente nas minhas aulas de Banco de Dados no SENAC para desenvolver este artigo. Frequentemente, os alunos me perguntam por que recomendo o uso do tipo de dado VARCHAR2 para colunas que armazenam textos de tamanho variável, em vez do tipo CHAR. Essa dúvida é comum e pode parecer simples à primeira vista, mas a escolha entre esses dois tipos pode impactar diretamente o desempenho do banco de dados.

O CHAR sempre armazena o número fixo de caracteres que for definido, completando os espaços que sobraram. Já o VARCHAR2 armazenada o conteúdo inserido, ocupando apenas o espaço necessário para o mesmo.

Imagine uma situação em que uma coluna é definida como CHAR(200) para armazenar nomes. Ao inserir o nome 'Paulo', que tem 5 letras, o Oracle armazenará esse valor com 195 espaços em branco à direita para completar os 200 caracteres definidos no tipo CHAR. 

Ou seja, mesmo que o conteúdo útil tenha apenas 5 caracteres, o espaço armazenado será equivalente a 200 caracteres.

Ao multiplicar esse comportamento em milhões de linhas, possivelmente teremos:
  • Aumento de I/O;
  • Desperdício de espaço em disco e cache;
  • Maior lentidão em consultas;

Para exemplificar essa situação, será feita uma simulação no Oracle, criando duas tabelas de teste, uma com coluna do tipo CHAR(100), outra do tipo VARCHAR2(100) e serão inseridos alguns milhões de registros para podermos simular. 

SQL>
SQL> CREATE TABLE teste_char (
  nome CHAR(100)
);
  2    3
Table created.

SQL>
SQL> CREATE TABLE teste_varchar (
  nome VARCHAR2(100)
);
  2    3
Table created.

SQL>
SQL> BEGIN
        FOR a IN 1 .. 10 LOOP
                FOR i IN 1 .. 200000 LOOP
                        INSERT INTO teste_char VALUES ('João');
                        INSERT INTO teste_varchar VALUES ('João');
                END LOOP;
                COMMIT;
        END LOOP;
END;
/         2    3    4    5    6    7    8    9   10


PL/SQL procedure successfully completed.

SQL> SQL>

A primeira verificação será para consultar o espaço ocupado por cada uma das tabelas após a inserção dos dados.

SQL>
SQL> col segment_name for a30
SELECT segment_name, bytes/1024/1024 AS tamanho_mb
FROM user_segments
WHERE segment_name IN ('TESTE_CHAR', 'TESTE_VARCHAR');SQL>   2    3

SEGMENT_NAME                   TAMANHO_MB
------------------------------ ----------
TESTE_CHAR                            232
TESTE_VARCHAR                          33

SQL>

Aqui podemos notar que para armazenar a mesma quantidade de registros a tabela com o campo CHAR ocupou 232MB, enquanto a com VARCHAR2 apenas 33MB.

Agora vamos verificar como fica a performance ao realizar uma consulta em cada uma das tabelas.

SQL>
SQL> SET TIMING ON
SQL> SELECT COUNT(*) FROM teste_char WHERE nome = 'João';

  COUNT(*)
----------
   2000000

Elapsed: 00:00:01.13
SQL>
SQL> SELECT COUNT(*) FROM teste_varchar WHERE nome = 'João';

  COUNT(*)
----------
   2000000

Elapsed: 00:00:00.22
SQL>

Enquanto a consulta na tabela com CHAR levou 1,13 segundos a consulta na tabela com VARCHAR2 levou 0,22 segundos. A diferença de tempo ocorre devido ao CHAR preencher os espaços (padding).

Então, quando usar o CHAR ?

Apenas quando o conteúdo tem tamanho fixo garantido e o uso de espaço previsível for um requisito, como:

  • Códigos ISO de país (ex: 'BR', 'US')
  • Flags (Y / N)
  • Dados que serão processados em massa com alinhamento binário (raro)

Comentários