Pergunta

Sei que CHAR é recomendado se todos os meus valores tiverem largura fixa.Mas e daí?Por que não escolher VARCHAR para todos os campos de texto, apenas por segurança.

Foi útil?

Solução

Geralmente escolha CARACTERES se todas as linhas tiverem perto do Mesmo comprimento.Escolha VARCHAR quando o o comprimento varia significativamente.CHAR também pode ser um pouco mais rápido porque todas as linhas têm o mesmo comprimento.

Isso varia de acordo com a implementação do banco de dados, mas geralmente VARCHAR usa mais um ou dois bytes de armazenamento (para comprimento ou terminação) além dos dados reais.Então (supondo que você esteja usando um conjunto de caracteres de um byte) armazenando a palavra "FooBar"

  • CHAR(6) = 6 bytes (sem sobrecarga)
  • VARCHAR(10) = 8 bytes (2 bytes de sobrecarga)
  • CHAR(10) = 10 bytes (4 bytes de sobrecarga)

Resumindo CARACTERES pode ser mais rápido e mais eficiente em termos de espaço para dados de comprimento relativamente igual (dentro de uma diferença de comprimento de dois caracteres).

Observação:O Microsoft SQL possui 2 bytes de sobrecarga para um VARCHAR.Isso pode variar de banco de dados para banco de dados, mas geralmente há pelo menos 1 byte de sobrecarga necessário para indicar comprimento ou EOL em um VARCHAR.

Como foi apontado por Gaven nos comentários, se você estiver usando um conjunto de caracteres multibyte e de comprimento variável como UTF8, então CHAR armazena o número máximo de bytes necessários para armazenar o número de caracteres.Portanto, se UTF8 precisar de no máximo 3 bytes para armazenar um caractere, então CHAR(6) será fixado em 18 bytes, mesmo armazenando apenas caracteres latin1.Portanto, neste caso, VARCHAR se torna uma escolha muito melhor.

Outras dicas

Se você estiver trabalhando comigo e com a Oracle, provavelmente eu faria você usar varchar em quase todas as circunstâncias.A suposição de que char usa menos poder de processamento do que varchar pode ser verdade... por enquanto... mas os mecanismos de banco de dados melhoram com o tempo e esse tipo de regra geral cria um "mito" futuro.

Outra coisa:Nunca vi um problema de desempenho porque alguém decidiu seguir varchar.Você aproveitará muito melhor seu tempo escrevendo bons códigos (menos chamadas ao banco de dados) e SQL eficiente (como funcionam os índices, como o otimizador toma decisões, por que exists mais rápido que in geralmente...).

Pensamento final:Tenho visto todos os tipos de problemas com o uso de CHAR, pessoas procurando por '' quando deveriam procurar '', ou pessoas procurando por 'FOO' quando deveriam procurar por 'FOO (um monte de espaços aqui)', ou pessoas que não cortam os espaços em branco finais, ou bugs com Powerbuilder adicionando até 2.000 espaços em branco ao valor retornado de um procedimento Oracle.

Além dos benefícios de desempenho, CHAR pode ser usado para indicar que todos os valores deve ter o mesmo comprimento, por exemplo, uma coluna para os EUA.abreviaturas de estado.

Char é um pouco mais rápido, então se você tem uma coluna que você SABE que terá um determinado comprimento, use char.Por exemplo, armazenar (M)ale/(F)emale/(U)nknown para gênero ou 2 caracteres para um estado dos EUA.

NChar ou Char apresentam melhor desempenho que suas alternativas var?

Ótima pergunta.A resposta simples é sim em certas situações.Vamos ver se isso pode ser explicado.

Obviamente todos nós sabemos que se eu criar uma tabela com uma coluna de varchar(255) (vamos chamar esta coluna de myColumn) e inserir um milhão de linhas, mas colocar apenas alguns caracteres em myColumn para cada linha, a tabela será muito menor (no geral número de páginas de dados necessárias para o mecanismo de armazenamento) do que se eu tivesse criado myColumn como char(255).Sempre que eu fizer uma operação (DML) nessa tabela e solicitar muitas linhas, será mais rápido quando myColumn for varchar porque não preciso mover em torno de todos aqueles espaços "extras" no final.Mova, como quando o SQL Server faz classificações internas, como durante uma operação distinta ou de união, ou se escolhe uma mesclagem durante seu plano de consulta, etc.Mover também pode significar o tempo que leva para levar os dados do servidor para o meu PC local ou para outro computador ou onde quer que sejam consumidos.

Mas há alguma sobrecarga no uso do varchar.O SQL Server precisa usar um indicador de dois bytes (overhead) para, em cada linha, saber quantos bytes o myColumn daquela linha específica contém.Não são os 2 bytes extras que apresentam o problema, é a necessidade de "decodificar" o comprimento dos dados em myColumn em cada linha.

Na minha experiência, faz mais sentido usar char em vez de varchar nas colunas que serão unidas nas consultas.Por exemplo a chave primária de uma tabela, ou alguma outra coluna que será indexada.CustomerNumber em uma tabela demográfica, ou CodeID em uma tabela de decodificação, ou talvez OrderNumber em uma tabela de pedidos.Ao usar char, o mecanismo de consulta pode executar a junção mais rapidamente porque pode fazer aritmética de ponteiro direto (deterministicamente) em vez de ter que mover seus ponteiros por uma quantidade variável de bytes enquanto lê as páginas.Eu sei que posso ter perdido você na última frase.As junções no SQL Server são baseadas na idéia de "predicados". Um predicado é uma condição.Por exemplo, myColumn = 1 ou OrderNumber < 500.

Portanto, se o SQL Server estiver executando uma instrução DML e os predicados ou "chaves" unidas tiverem um comprimento fixo (char), o mecanismo de consulta não precisará fazer tanto trabalho para corresponder as linhas de uma tabela com as linhas de outra mesa.Não será necessário descobrir quanto tempo os dados estão na linha e depois percorrer a string para encontrar o final.Tudo isso leva tempo.

Agora tenha em mente que isso pode facilmente ser mal implementado.Já vi char usado para campos de chave primária em sistemas online.A largura deve ser mantida pequena, ou seja,char(15) ou algo razoável.E funciona melhor em sistemas on-line porque normalmente você está recuperando ou fazendo upser apenas em um pequeno número de linhas, portanto, ter que "rtrim" os espaços finais que você obterá no conjunto de resultados é uma tarefa trivial, em vez de ter que juntar milhões de linhas de uma tabela para milhões de linhas em outra tabela.

Outra razão pela qual o CHAR faz sentido em relação ao varchar em sistemas online é que ele reduz as divisões de páginas.Ao usar char, você está essencialmente "reservando" (e desperdiçando) esse espaço, portanto, se um usuário aparecer mais tarde e colocar mais dados nessa coluna, o SQL já alocou espaço para ele e por aí vai.

Outro motivo para usar CHAR é semelhante ao segundo motivo.Se um programador ou usuário fizer uma atualização em "lote" para milhões de linhas, adicionando alguma frase a um campo de nota, por exemplo, você não receberá uma ligação do seu DBA no meio da noite perguntando por que suas unidades estão cheias.Em outras palavras, leva a um crescimento mais previsível do tamanho de um banco de dados.

Portanto, essas são três maneiras pelas quais um sistema online (OLTP) pode se beneficiar do char em vez do varchar.Eu quase nunca uso char em um cenário de warehouse/análise/OLAP porque geralmente você tem tantos dados que todas essas colunas char podem resultar em muito espaço desperdiçado.

Tenha em mente que char pode tornar seu banco de dados muito maior, mas a maioria das ferramentas de backup possui compactação de dados, portanto seus backups tendem a ter aproximadamente o mesmo tamanho como se você tivesse usado varchar.Por exemplo LiteSpeed ​​​​ou RedGate SQL Backup.

Outro uso é em visualizações criadas para exportar dados para um arquivo de largura fixa.Digamos que eu precise exportar alguns dados para um arquivo simples para ser lido por um mainframe.Tem largura fixa (não delimitada).Eu gosto de armazenar os dados na minha tabela de "teste" como varchar (consumindo menos espaço no meu banco de dados) e depois usar uma visualização para CAST tudo em seu equivalente char, com o comprimento correspondente à largura da largura fixa para essa coluna .Por exemplo:

create table tblStagingTable (
pkID BIGINT (IDENTITY,1,1),
CustomerFirstName varchar(30),
CustomerLastName varchar(30),
CustomerCityStateZip varchar(100),
CustomerCurrentBalance money )

insert into tblStagingTable
(CustomerFirstName,CustomerLastName, CustomerCityStateZip) ('Joe','Blow','123 Main St Washington, MD 12345', 123.45)

create view vwStagingTable AS
SELECT CustomerFirstName = CAST(CustomerFirstName as CHAR(30)),
CustomerLastName = CAST(CustomerLastName as CHAR(30)),
CustomerCityStateZip = CAST(CustomerCityStateZip as CHAR(100)),
CustomerCurrentBalance = CAST(CAST(CustomerCurrentBalance as NUMERIC(9,2)) AS CHAR(10))

SELECT * from vwStagingTable

Isso é legal porque internamente meus dados ocupam menos espaço porque estão usando varchar.Mas quando eu uso DTS ou SSIS ou mesmo apenas recortar e colar do SSMS no Bloco de Notas, posso usar a visualização e obter o número certo de espaços à direita.No DTS costumávamos ter um recurso chamado, caramba, esqueci que acho que se chamava "sugerir colunas" ou algo assim.No SSIS você não pode mais fazer isso, você precisa definir tediosamente o gerenciador de conexões de arquivo simples.Mas como você tem sua visualização configurada, o SSIS pode saber a largura de cada coluna e pode economizar muito tempo ao criar suas tarefas de fluxo de dados.

Então, resultado final...use varchar.Há um número muito pequeno de motivos para usar char e é apenas por motivos de desempenho.Se você tiver um sistema com centenas de milhões de linhas, verá uma diferença notável se os predicados forem determinísticos (char), mas para a maioria dos sistemas usar char é simplesmente desperdiçar espaço.

Espero que ajude.Jeff

Existem benefícios de desempenho, mas aqui está um que não foi mencionado:migração de linha.Com char, você reserva todo o espaço com antecedência. Digamos que você tenha um char (1000) e armazene 10 caracteres, você usará todos os 1000 caracteres de espaço.Em um varchar2(1000), você usará apenas 10 caracteres.O problema surge quando você modifica os dados.Digamos que você atualize a coluna para conter 900 caracteres.É possível que o espaço para expandir o varchar não esteja disponível no bloco atual.Nesse caso, o mecanismo de banco de dados deve migrar a linha para outro bloco e apontar no bloco original para a nova linha no novo bloco.Para ler esses dados, o mecanismo do banco de dados terá agora que ler 2 blocos.
Ninguém pode dizer equivocadamente que varchar ou char são melhores.Há espaço para compensação de tempo e consideração se os dados serão atualizados, especialmente se houver uma boa chance de que aumentem.

Há uma diferença entre a otimização inicial do desempenho e o uso de um tipo de regra de prática recomendada.Se você estiver criando novas tabelas onde sempre terá um campo de comprimento fixo, faz sentido usar CHAR, você deveria usá-lo nesse caso.Esta não é uma otimização inicial, mas sim a implementação de uma regra prática (ou prática recomendada).

ou seja- Se você tiver um campo de estado de 2 letras, use CHAR(2).Se você tiver um campo com os nomes reais dos estados, use VARCHAR.

Eu escolheria varchar, a menos que a coluna armazene valores fixos como o código do estado dos EUA - que sempre tem 2 caracteres e a lista de códigos válidos dos estados dos EUA não muda com frequência :).

Em todos os outros casos, mesmo como armazenar senha com hash (que tem comprimento fixo), eu escolheria varchar.

Por que - a coluna do tipo char é sempre preenchida com espaços, o que torna a coluna minha_coluna definido como char(5) com valor 'ABC' dentro da comparação:

my_column = 'ABC' -- my_column stores 'ABC  ' value which is different then 'ABC'

falso.

Esse recurso pode levar a muitos bugs irritantes durante o desenvolvimento e dificultar os testes.

CHAR ocupa menos espaço de armazenamento que VARCHAR se todos os valores de dados nesse campo tiverem o mesmo comprimento.Agora, talvez em 2009, um banco de dados de 800 GB seja o mesmo para todos os efeitos e propósitos que um banco de dados de 810 GB se você convertesse os VARCHARs em CHARs, mas para strings curtas (1 ou 2 caracteres), CHAR ainda é uma "melhor prática" do setor, eu diria.

Agora, se você observar a grande variedade de tipos de dados que a maioria dos bancos de dados fornece, mesmo apenas para números inteiros (bit, tiny, int, bigint), EXISTEM razões para escolher um em vez do outro.Simplesmente escolher bigint todas as vezes é, na verdade, ignorar um pouco os propósitos e usos do campo.Se um campo representa simplesmente a idade de uma pessoa em anos, um bigint é um exagero.Agora não é necessariamente “errado”, mas não é eficiente.

Mas é um argumento interessante e, à medida que os bancos de dados melhoram com o tempo, pode-se argumentar que CHAR vs VARCHAR se torna menos relevante.

Mantenho o comentário de Jim McKeeth.

Além disso, a indexação e a varredura completa da tabela serão mais rápidas se sua tabela tiver apenas colunas CHAR.Basicamente, o otimizador será capaz de prever o tamanho de cada registro se ele tiver apenas colunas CHAR, enquanto precisa verificar o valor do tamanho de cada coluna VARCHAR.

Além disso, se você atualizar uma coluna VARCHAR para um tamanho maior que seu conteúdo anterior, poderá forçar o banco de dados a reconstruir seus índices (porque forçou o banco de dados a mover fisicamente o registro no disco).Enquanto estiver com colunas CHAR, isso nunca acontecerá.

Mas você provavelmente não se importará com o impacto no desempenho, a menos que sua mesa seja enorme.

Lembre-se das sábias palavras de Djikstra.A otimização precoce do desempenho é a raiz de todos os males.

Muitas pessoas apontaram que se você souber o comprimento exato do valor, usar CHAR traz alguns benefícios.Mas embora armazenar estados dos EUA como CHAR(2) seja ótimo hoje, quando você recebe a mensagem do setor de vendas de que “Acabamos de fazer nossa primeira venda para a Austrália”, você se sente em um mundo de dor.Sempre costumo superestimar quanto tempo acho que os campos precisarão ter, em vez de fazer uma estimativa "exata" para cobrir eventos futuros.VARCHAR me dará mais flexibilidade nesta área.

Há uma pequena sobrecarga de processamento no cálculo do tamanho real necessário para um valor de coluna e na alocação de espaço para um Varchar; portanto, se você tiver certeza de quanto tempo o valor sempre terá, é melhor usar Char e evitar o acerto.

É a clássica compensação entre espaço e desempenho.

No MS SQL 2005, Varchar (ou NVarchar para idiomas que exigem dois bytes por caractere, ou seja, chinês) têm comprimento variável.Se você adicionar à linha depois de ela ter sido gravada no disco rígido, os dados serão localizados em um local não contíguo à linha original e levarão à fragmentação dos seus arquivos de dados.Isso afetará o desempenho.

Portanto, se o espaço não for um problema, então Char é melhor para desempenho, mas se você quiser manter o tamanho do banco de dados baixo, então varchars são melhores.

Acho que no seu caso provavelmente não há razão para não escolher Varchar.Isso lhe dá flexibilidade e, como foi mencionado por vários entrevistados, o desempenho é tal agora que, exceto em circunstâncias muito específicas, nós, meros mortais (ao contrário dos DBAs do Google), não notaremos a diferença.

Uma coisa interessante que vale a pena notar quando se trata de tipos de banco de dados é que o sqlite (um mini banco de dados popular com desempenho bastante impressionante) coloca tudo no banco de dados como uma string e digita instantaneamente.

Eu sempre uso o VarChar e geralmente o torno muito maior do que preciso.Por exemplo.50 para o primeiro nome, como você diz, por que não apenas por segurança.

Fragmentação.Char reserva espaço e VarChar não.A divisão de página pode ser necessária para acomodar a atualização do varchar.

Eu NUNCA usaria caracteres.Já tive esse debate com muitas pessoas e elas sempre trazem à tona o velho clichê de que char é mais rápido.Bem, eu digo, quanto mais rápido?Do que estamos falando aqui, milissegundos, segundos e, em caso afirmativo, de quantos?Você está me dizendo que porque alguém afirma que é alguns milissegundos mais rápido, deveríamos introduzir toneladas de bugs difíceis de corrigir no sistema?

Então, aqui estão alguns problemas que você encontrará:

Cada campo será preenchido, então você terá um código para sempre com RTRIMS em todos os lugares.Isso também representa um enorme desperdício de espaço em disco para campos mais longos.

Agora digamos que você tenha o exemplo quintessencial de um campo char de apenas um caractere, mas o campo é opcional.Se alguém passar uma string vazia para esse campo, ela se tornará um espaço.Assim, quando outro aplicativo/processo o consultar, eles obterão um único espaço, se não usarem rtrim.Já tivemos documentos xml, arquivos e outros programas, exibindo apenas um espaço, em campos opcionais e quebrando coisas.

Então agora você precisa garantir que está passando nulos e não uma string vazia para o campo char.Mas esse NÃO é o uso correto de nulo.Aqui está o uso de nulo.Digamos que você receba um arquivo de um fornecedor

Nome|Sexo|Cidade

Bob||Los Angeles

Se o gênero não for especificado, insira Bob, string vazia e Los Angeles na tabela.Agora digamos que você obtenha o arquivo e seu formato mude e o gênero não esteja mais incluído, mas estava no passado.

Nome|Cidade

Bob|Seattle

Bem, agora que o gênero não está incluído, eu usaria null.Varchars suportam isso sem problemas.

Char, por outro lado, é diferente.Você sempre tem que enviar null.Se você enviar uma string vazia, acabará com um campo que contém espaços.

Eu poderia continuar com todos os bugs que tive que corrigir em chars e em cerca de 20 anos de desenvolvimento.

Ao usar os valores Varchar, o SQL Server precisa de 2 bytes adicionais por linha para armazenar algumas informações sobre essa coluna, enquanto se você usar char, ele não precisa disso, a menos que você

Em alguns bancos de dados SQL, VARCHAR será preenchido até seu tamanho máximo para otimizar os deslocamentos. Isso acelera varreduras completas de tabelas e índices.

Por causa disso, você não economiza espaço usando um VARCHAR(200) em comparação com um CHAR(200)

Usar CHAR (NCHAR) e VARCHAR (NVARCHAR) traz diferenças na forma como o servidor de banco de dados armazena os dados.O primeiro introduz espaços em branco à direita;Encontrei problemas ao usá-lo com o operador LIKE nas funções SQL SERVER.Então eu tenho que deixar isso seguro usando VARCHAR (NVARCHAR) o tempo todo.

Por exemplo, se tivermos uma mesa TESTE(ID INT, Status CHAR(1)), e você escreve uma função para listar todos os registros com algum valor específico como o seguinte:

CREATE FUNCTION List(@Status AS CHAR(1) = '')
RETURNS TABLE
AS
RETURN
SELECT * FROM TEST
WHERE Status LIKE '%' + @Status '%'

Nesta função esperamos que ao colocarmos o parâmetro padrão a função retorne todas as linhas, mas na verdade isso não acontece.Alterar o tipo de dados @Status para VARCHAR resolverá o problema.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top