há uma vantagem em varchar (500) sobre varchar (8000)?

90

Eu li sobre isso nos fóruns do MSDN e aqui e ainda não estou certo. Acho que isso está correto: Varchar (max) será armazenado como um tipo de dados de texto, o que tem desvantagens. Então, digamos que seu campo tenha menos de 8.000 caracteres. Como um campo BusinessName em minha tabela de banco de dados. Na realidade, o nome de uma empresa provavelmente sempre terá (tirando um número da minha cartola) de 500 caracteres. Parece que muitos campos varchar que encontrei se enquadram na contagem de 8k caracteres.

Portanto, devo tornar esse campo um varchar (500) em vez de varchar (8000)? Pelo que entendi de SQL não há diferença entre os dois. Portanto, para facilitar a vida, gostaria de definir todos os meus campos varchar como varchar (8000). Isso tem alguma desvantagem?

Relacionado: Tamanho das colunas varchar (não achei que este respondesse minha pergunta).

Jcollum
fonte
6
Imagine tentar colocar o nome de uma empresa com 500 caracteres em um cartão de visita ... :)
Pôneis OMG
2
@OMG Ponies: toda vez que vejo seu nome de usuário, eu rio. Agora, o que você estava dizendo? (Brincadeira)
jcollum
4
@jcollum: SpaceMan Spiff sempre terá meu voto. Isso não é verdade - qualquer Calvin & Hobbes serve, mas especialmente os que esculpem neve. Ou o tiranossauro voando em um F-14. Mas estou divagando ...
Pôneis OMG

Respostas:

20

Do ponto de vista do processamento, não fará diferença usar varchar (8000) versus varchar (500). É mais um tipo de coisa de "boa prática" definir um comprimento máximo que um campo deve conter e tornar seu varchar desse comprimento. É algo que pode ser usado para auxiliar na validação de dados. Por exemplo, fazer com que uma abreviatura de estado tenha 2 caracteres ou um código postal / CEP com 5 ou 9 caracteres. Essa costumava ser uma distinção mais importante para quando seus dados interagiam com outros sistemas ou interfaces de usuário onde o comprimento do campo era crítico (por exemplo, um conjunto de dados de arquivo simples de mainframe), mas hoje em dia acho que é mais um hábito do que qualquer outra coisa.

BBlake
fonte
3
Faz sentido ... para coisas que naturalmente têm um comprimento máximo. Mas o que você faz quando o comprimento máximo não é óbvio? Por exemplo, o nome de uma empresa.
jcollum
2
Para algo assim, se eu não prevejo nenhuma maneira de prever o que o tamanho poderia ser, então eu geralmente vou com um varchar (8000) ou varchar (max), dependendo do tipo de dados
BBlake
4
Parece que isso faz uma diferença no desempenho, mesmo em 2017: dba.stackexchange.com/a/162117/1822
a_horse_with_no_name
1
Respostas mais recentes mostram que não são custos: ele afeta a lógica de otimização de resposta de Martin Smith e também considerar 8K total de problemas de tamanho de linhas mencionadas por gbn e Oliver .
Toolmaker Steve
124

Um exemplo em que isso pode fazer a diferença é que pode impedir uma otimização de desempenho que evita adicionar informações de versão de linha a tabelas com acionadores posteriores.

Isso é coberto pelo SQL Kiwi aqui

O tamanho real dos dados armazenados é irrelevante - é o tamanho potencial que importa.

Da mesma forma, se estiver usando tabelas com otimização de memória desde 2016, foi possível usar colunas LOB ou combinações de larguras de coluna que poderiam potencialmente exceder o limite de inrow, mas com uma penalidade.

As colunas (máximas) são sempre armazenadas fora da linha. Para outras colunas, se o tamanho da linha de dados na definição da tabela puder exceder 8.060 bytes, o SQL Server enviará as maiores colunas de comprimento variável para fora da linha. Novamente, não depende da quantidade de dados que você armazena lá.

Isso pode ter um grande efeito negativo no consumo de memória e no desempenho

Outro caso em que declarar larguras de coluna em excesso pode fazer uma grande diferença é se a tabela será processada usando o SSIS. A memória alocada para colunas de comprimento variável (não BLOB) é fixa para cada linha em uma árvore de execução e está de acordo com o comprimento máximo declarado das colunas, o que pode levar ao uso ineficiente de buffers de memória (exemplo) . Embora o desenvolvedor do pacote SSIS possa declarar um tamanho de coluna menor do que a fonte, é melhor fazer essa análise antecipadamente e aplicá-la lá.

De volta ao próprio mecanismo do SQL Server, um caso semelhante é que, ao calcular a concessão de memória a ser alocada para SORToperações, o SQL Server presume que as varchar(x)colunas irão, em média, consumir x/2bytes.

Se a maioria de suas varcharcolunas estiver mais cheia do que isso, isso pode levar ao sortextravasamento das operações tempdb.

No seu caso, se suas varcharcolunas forem declaradas como 8000bytes, mas na verdade tiverem conteúdo muito menor do que isso, sua consulta terá memória alocada que não requer, o que é obviamente ineficiente e pode levar a esperas por concessões de memória.

Isso é abordado na Parte 2 do Webcast 1 de Workshops de SQL, que pode ser baixado aqui ou veja abaixo.

use tempdb;

CREATE TABLE T(
id INT IDENTITY(1,1) PRIMARY KEY,
number int,
name8000 VARCHAR(8000),
name500 VARCHAR(500))

INSERT INTO  T 
(number,name8000,name500)
SELECT number, name, name /*<--Same contents in both cols*/
FROM master..spt_values

SELECT id,name500
FROM T
ORDER BY number

Captura de tela

SELECT id,name8000
FROM T
ORDER BY number

Captura de tela

Martin Smith
fonte
1
então, se quase todos os meus valores são 3 ou 4 caracteres, não podem exceder 4 caracteres nunca, e eu quero evitar "operações de classificação transbordando para tempdb", declararei minha coluna VARCHAR (8) e usarei uma restrição CHECK para impor essa coluna a largura não pode exceder 4 caracteres. O que você acha?
AK
12
@AlexKuznetsov - Para essa situação, eu os declararia como char(4)já que há uma sobrecarga de 2 bytes por coluna de variável.
Martin Smith
9

Além das melhores práticas (resposta de BBlake)

  • Você recebe avisos sobre o tamanho máximo da linha (8060) bytes e largura do índice (900 bytes) com DDL
  • DML morrerá se você exceder esses limites
  • ANSI PADDING ON é o padrão, então você pode acabar armazenando uma carga inteira de espaços em branco
gbn
fonte
38
Apenas para esclarecer sobre ANSI PADDING ON: ao usar os tipos nvarchare varchar, isso significa apenas que os espaços finais são preservados na inserção - não que os valores são preenchidos com espaços para o tamanho da coluna, como em chare nchar.
Ben M
9

Existem algumas desvantagens em colunas grandes que são um pouco menos óbvias e podem pegar você um pouco mais tarde:

  • Todas as colunas que você usa em um INDEX - não deve exceder 900 bytes
  • Todas as colunas em uma cláusula ORDER BY não podem exceder 8060 bytes. Isso é um pouco difícil de entender, pois só se aplica a algumas colunas. Consulte o limite de tamanho de linha do SQL 2008 R2 excedido para obter detalhes)
  • Se o tamanho total da linha exceder 8060 bytes, você obterá um " derramamento de página " para essa linha. Isso pode afetar o desempenho (uma página é uma unidade de alocação no SQLServer e é fixada em 8000 bytes + alguma sobrecarga. Exceder isso não será grave, mas é perceptível e você deve tentar evitá-lo se puder)
  • Muitas outras estruturas de dados internas, buffers e, por último, não menos importante, suas próprias variáveis ​​e variáveis ​​de tabela precisam espelhar esses tamanhos. Com tamanhos excessivos, a alocação excessiva de memória pode afetar o desempenho

Como regra geral, tente ser conservador com a largura da coluna. Se se tornar um problema, você pode facilmente expandi-lo para atender às necessidades. Se você notar problemas de memória mais tarde, reduzir uma coluna grande mais tarde pode se tornar impossível sem perder dados e você não saberá por onde começar.

Em seu exemplo de nomes de empresas, pense onde você consegue exibi-los. Existe realmente espaço para 500 caracteres ?? Caso contrário, não faz sentido armazená-los como tais. http://en.wikipedia.org/wiki/List_of_companies_of_the_United_States lista alguns nomes de empresas e o máximo é cerca de 50 caracteres. Então, eu usaria 100 para o máximo da coluna. Talvez mais como 80.

Oliver
fonte
2

O ideal é que você deseje ser menor do que isso, até um tamanho razoável (500 não é um tamanho razoável) e garantir que a validação do cliente detecte quando os dados ficarão muito grandes e envie um erro útil.

Embora o varchar não vá realmente reservar espaço no banco de dados para o espaço não utilizado, lembro-me de versões do SQL Server que reclamaram que as linhas do banco de dados eram mais largas do que um certo número de bytes (não me lembro da contagem exata) e realmente descartando quaisquer dados não cabem. Um certo número desses bytes foi reservado para coisas internas ao SQL Server.

Otis
fonte
verdade, isso costumava ser uma preocupação muito maior também. Mas hoje em dia o espaço é muito barato, então não acho que seja uma preocupação tão grande assim, pelo menos do meu ponto de vista.
BBlake
1
@jcollum: Em seu exemplo, 500 não parece um tamanho razoável para o nome de uma empresa.
Otis
1
@BBlake: Independentemente do custo de armazenamento, se o SQL Server ainda tiver restrições de tamanho de linha, não importa quanto armazenamento você tenha. Você poderia armazenar tudo em textblobs, mas existem algumas operações SQL que você não pode fazer em um blob que pode ser feito em um varchar.
Otis
2
@Otis: meu ponto é o seguinte: não há nenhuma restrição real sobre o tamanho do nome de uma empresa. A menos que haja uma lei em algum lugar. Então, nesse caso, eu faria esse campo varchar (8000) e encerraria o dia. Meu pensamento é assim: Restrição real? varchar (x). Nenhuma restrição real? varchar (8000).
jcollum
24
Achei que cerca de 30 caracteres eram bons para nomes de cidades, até que vi El Pueblo de Nuestra Señora la Reina de los Ángeles del Río de Porciúncula
StuartLC