Quais são as práticas recomendadas atuais em relação ao dimensionamento de varchar no SQL Server?

12

Estou tentando entender a melhor maneira de decidir o tamanho das colunas varchar, tanto do ponto de vista de armazenamento quanto de desempenho.

Desempenho
Da minha pesquisa, pareceesse varchar (max) só deve ser usado se você realmente precisar; isto é, se a coluna deve acomodar mais de 8000 caracteres, uma razão é a falta de indexação (embora eu seja um pouco desconfiado de indexar nos campos varchar em geral. Sou bastante novo nos princípios do banco de dados, então talvez isso seja infundado ) e compactação (mais uma preocupação de armazenamento). De fato, em geral, as pessoas parecem recomendar apenas o uso do que você precisa, ao fazer o varchar (n) .... oversizing é ruim, porque as consultas devem levar em conta o tamanho máximo possível. Mas também foi afirmado que o mecanismo usará metade do tamanho indicado como uma estimativa do tamanho real médio dos dados. Isso implica que se deve determinar, a partir dos dados, qual é o tamanho médio, dobrá-lo e usá-lo como n. Para dados com variabilidade muito baixa, mas diferente de zero, isso implica em um tamanho 2x maior do que o tamanho máximo, o que parece muito, mas talvez não seja? Insights seriam apreciados.

Armazenamento
Depois de ler sobre como o armazenamento em linha e o armazenamento fora de linha funciona, e tendo em mente que o armazenamento real é limitado a dados reais, parece-me realmente que a escolha de n tem pouca ou nenhuma influência no armazenamento (além de certificando-se de que é grande o suficiente para armazenar tudo). Mesmo usando varchar (max) não deve ter nenhum impacto no armazenamento. Em vez disso, um objetivo pode ser limitar o tamanho real de cada linha de dados a ~ 8000 bytes, se possível. Essa é uma leitura precisa das coisas?

Contexto
Alguns dados de nossos clientes flutuam um pouco, então geralmente tornamos as colunas um pouco mais amplas do que precisam, digamos 15 a 20% maiores, para essas colunas. Fiquei imaginando se havia outras considerações especiais; por exemplo, alguém com quem trabalho me disse para usar tamanhos 2 ^ n - 1 (embora eu não tenha encontrado nenhuma evidência disso ...)

Eu estou falando sobre a criação da tabela inicial. Um cliente nos dirá que eles começarão a nos enviar uma nova tabela e enviar dados de amostra (ou apenas o primeiro conjunto de dados de produção), para os quais analisamos e fazemos uma tabela para armazenar os dados. Queremos fazer a tabela do nosso lado para lidar com futuras importações e com o que está na amostra. Porém, certas linhas tendem a ficar mais longas, então as protegemos.

A questão é quanto e existem diretrizes técnicas?

aristotle2600
fonte
O MongoDB usa alocação de disco 2 ^ n para um documento. O SQL Server não usa essa estratégia.
Michael Green

Respostas:

19

Independentemente do tipo de dados específico, você precisa poder armazenar o que o aplicativo solicitar para ser armazenado. Você não pode especificar algo menor que o tamanho máximo do que realmente será salvo.

Você também não precisa nem deseja especificar um comprimento de coluna maior que o tamanho real máximo que será armazenado por vários motivos: consulta à alocação de memória, potencialmente preenchendo o tamanho máximo de linha e não deixando espaço para adicionar colunas o futuro etc.

É verdade que a string de comprimento variável e as colunas binárias não têm a implicação de armazenamento que os tipos de dados de comprimento fixo (string / binary / numeric / date / etc) possuem (embora algumas dessas implicações possam ser anuladas por meio de compactação de dados ou uso da SPARSEdefinição de coluna opção). No entanto, como você apontou, mesmo se não houver implicação direta de armazenamento, ainda há a implicação de desempenho de superestimar a memória necessária para consultas.

Seja sensato. Use apenas o que precisar. Considerações podem ser feitas se houver uma alta probabilidade de que o comprimento da coluna precise aumentar no futuro próximo, mas lembre-se de que é mais fácil expandir o tamanho de uma coluna do que reduzir o tamanho. Sim, algum trabalho estará envolvido, mas, como esse trabalho é apenas "potencial", enquanto as implicações de desempenho do sobredimensionamento são "reais", geralmente é melhor definir colunas com base no que você realmente precisa, e não no que você talvez meio -sorta acho que você pode precisar no futuro. Muitas mudanças mencionadas nunca acontecem e, muitas vezes, as mudanças necessárias não podem ser previstas. Vá com o que você sabe.

Em vez disso, um objetivo pode ser limitar o tamanho real de cada linha de dados a ~ 8000 bytes, se possível.

Não sei exatamente o que você está recebendo aqui. O SQL Server limitará fisicamente você a pouco mais de 8000 bytes. Utilizando tipos LOB - VARCHAR(MAX), NVARCHAR(MAX), VARBINARY(MAX), XML, e a preterida TEXT, NTEXTe IMAGEtipos - permitir que ultrapasse o limite de tamanho de página inicial, mas que é apenas devido à colocação de um ponteiro (16 ou mais bytes, dependendo do tipo e dependendo da tamanho do valor armazenado off-line ao usar os MAXtipos). O limite físico real da página de dados não foi alterado.

Seu objetivo deve ser usar a menor quantidade de espaço físico para armazenar o que o aplicativo / empresa precisa armazenar sem interromper ou truncar, de modo que o valor incompleto perca significado ou cause problemas a jusante. Se você precisar armazenar um número de 12.000 caracteres, use VARCHAR(MAX)porque é isso que é necessário. Se você estiver armazenando um número de telefone ou código postal, seria imprudente VARCHAR(100)e irresponsável VARCHAR(MAX).

alguns dados de nossos clientes flutuam um pouco; portanto, geralmente tornamos as colunas um pouco mais amplas do que precisam, digamos 15 a 20% maiores para essas colunas. Fiquei imaginando se havia outras considerações especiais;

Todos os sistemas não têm pelo menos alguns dados que flutuam? Qualquer sistema que armazene o nome de uma pessoa se qualificaria, certo? Há uma variação bastante grande no comprimento dos nomes. E então você tem alguém como Prince e muda seu nome para um símbolo e agora você tem um problema completamente diferente que não é longo. É assim que as coisas são.

Mas, para brincar de advogado do diabo por um momento: como o valor "15-20% maior do que o necessário" não pode ser o valor realmente necessário ? Digamos que haja uma discussão sobre a adição de uma nova coluna, e alguém sugira 50 caracteres, e outra pessoa diga: "bem, 20% a mais é 60, então vamos fazer 60 porque alguém pode ter 60". Se é verdade que um cliente pode ter 60, 60 é, e sempre foi, o valor real necessário, e 50 estava errado o tempo todo.

Obviamente, ajudaria se houvesse alguma indicação quanto à fonte dos dados, porque:

  1. se você criar "URL" 1024 e alguém precisar de 1060, ele precisará ser 1060 (da mesma forma, se você criar URL VARCHARe receber reclamações de que está atrapalhando caracteres Unicode que agora são permitidos em nomes de domínio, é necessário NVARCHAR), mas
  2. se alguém quiser adicionar 1000 caracteres a um campo de comentário com limite de 500 caracteres, ainda precisará ser 500. As pessoas podem ser menos detalhadas nos comentários (um grande desafio para mim ;-), mas é ProductSKUmelhor que seja grande o suficiente para caber em todos dos SKUs do cliente.

Eu estou falando sobre a criação da tabela inicial. Um cliente nos dirá que eles começarão a nos enviar uma nova tabela e enviar dados de amostra (ou apenas o primeiro conjunto de dados de produção), para os quais analisamos e fazemos uma tabela para armazenar os dados. Queremos fazer a tabela do nosso lado para lidar com futuras importações e com o que está na amostra. Porém, certas linhas tendem a ficar mais longas, então as protegemos. A questão é quanto e existem diretrizes técnicas?

Você está fazendo muitas suposições aqui. Certamente, alguns campos podem ficar maiores. Mas, novamente, eles podem não. Ou, alguns podem ficar menores. Alguns podem mudar de não-Unicode para Unicode (uma vez que percebem que o mundo está ficando menor e não se pode presumir que os sobrenomes só terão caracteres básicos em inglês ASCII / EUA). Ou eles podem parar de enviar um campo. Ou eles podem adicionar um ou mais campos no futuro. Qualquer combinação disso e de outras coisas. Então, por que focar apenas nas VARCHARcolunas? E se eles estiverem enviando um INTvalor no momento e em um ou dois anos atingirem o valor máximo e começarem a enviar um BIGINT? E se eles tiverem um campo "status" com valores de 0 a 5. Você apenas assumiráINTque é "acolchoado", pois permite o crescimento, mas provavelmente deveria ser TINYINT?

A única coisa que você pode prever com segurança é que tentar prever como os dados de seus clientes serão alterados estará errado com mais frequência do que o correto. E estar correto é uma questão de sorte / coincidência (se não for sorte, basta ir jogar na loteria;).

Portanto, a diretriz é:

  1. Não perca tempo e energia tentando responder a uma pergunta sem resposta.
  2. Em vez disso, concentre-se em obter o máximo de informações possível sobre os dados reais de seu cliente e siga em frente (isto é, tomada de decisão baseada em dados ;-).

Você já tem dados de exemplo, ótimo. Mas não esqueça que você também tem as informações de contato do seu cliente: telefone e / ou e-mail. Contate-os! Peça a eles suas especificações de dados (assim como seu sistema, os dados atualmente em seu sistema podem ter um comprimento máximo de 35, mas o sistema o definiu como VARCHAR(50)e o sistema aceitará esse comprimento; nesse caso, você deve usar 50) E pergunte se eles têm algum plano de curto prazo para alterar e desses tipos de dados (tipo e / ou tamanho).

Solomon Rutzky
fonte
11
Concordo com Solomon, @ Aristotle2600 - no entanto, você pode querer dar uma olhada em minha resposta em uma pergunta sobre as diferenças entre um varchar(255)e um varchar(256)para algumas outras considerações
Max Vernon
Obrigado, tive a impressão de que seria algo assim e "usar apenas o que você precisa" é apenas uma boa prática de gerenciamento de recursos. Porém, alguns dados de nossos clientes flutuam um pouco, então geralmente tornamos as colunas um pouco mais amplas do que precisam, digamos 15 a 20% maiores, para essas colunas. Fiquei imaginando se havia outras considerações especiais; por exemplo, alguém com quem trabalho me disse para usar 2 ^ n - 1 tamanhos (embora eu não tenha encontrado nenhuma evidência disso ...). Mas parece que não há outra coisa senão manter as coisas o menor possível.
precisa
11
@ aristotle2600 Não sabe ao certo como aplicar "2 ^ n - 1", mas eu ainda teria que perguntar: é teoricamente possível criar algo maior do que precisa ? Esse tamanho 15-20% maior não seria do tamanho necessário para não quebrar? ;-). Tenho certeza de que ajudaria se você fosse mais explícito na fonte dos dados, porque a) se você criar "URL" 1024 e alguém precisar de 1060, será necessário 1060, mas b) se alguém quiser adicionar 1000 caracteres para um campo de comentário com limite de 500 caracteres, ele ainda precisa ser apenas 500. As pessoas podem inserir menos nos comentários, mas é melhor que o SKU do produto seja grande o suficiente.
Solomon Rutzky
@ aristotle2600 Acabei de adicionar alguns de seus comentários aqui à pergunta, pois eles fornecem um bom contexto. Eu também acrescentou coisas para o fim da minha resposta :)
Solomon Rutzky
Muito obrigado pela sua resposta! Sim, nomes e endereços flutuam. Quanto ao paradoxo cada vez maior de 20%, entendo o que você quer dizer, mas estou falando sobre a criação da tabela inicial. Um cliente nos dirá que eles começarão a nos enviar uma nova tabela e enviar dados de amostra (ou apenas o primeiro conjunto de dados de produção), para os quais analisamos e fazemos uma tabela para armazenar os dados. Queremos fazer a tabela do nosso lado para lidar com futuras importações e com o que está na amostra. Mas, como certas linhas tendem a ficar mais longas, nós as protegemos. A questão é quanto e existem diretrizes técnicas?
precisa