Hesito em acrescentar mais uma resposta aqui, pois já existem algumas, mas é preciso ressaltar alguns pontos que ainda não foram feitos ou que não foram feitos claramente.
Primeiro: Do não usar sempre NVARCHAR. Essa é uma atitude / abordagem muito perigosa e muitas vezes dispendiosa. E não é melhor dizer " Nunca use cursores", pois às vezes eles são os meios mais eficientes de resolver um problema específico, e a solução comum de fazer um WHILEloop quase sempre será mais lenta do que um Cursor feito corretamente .
O único momento em que você deve usar o termo "sempre" é quando aconselhado a "sempre fazer o que é melhor para a situação". É óbvio que é difícil determinar, principalmente quando se tenta equilibrar os ganhos de curto prazo no tempo de desenvolvimento (gerente: "precisamos desse recurso - que você não conhecia até agora - uma semana atrás!") Por muito tempo. custos de manutenção a médio prazo (gerente que inicialmente pressionou a equipe para concluir um projeto de 3 meses em um sprint de 3 semanas: "por que estamos tendo esses problemas de desempenho? Como poderíamos ter feito o X sem flexibilidade? Não podemos pagar um sprint ou dois para corrigir isso. O que podemos fazer em uma semana para voltar aos itens prioritários? E, definitivamente, precisamos gastar mais tempo no design para que isso não continue acontecendo! ").
Segundo: a resposta do @ gbn aborda alguns pontos muito importantes a serem considerados ao tomar determinadas decisões de modelagem de dados quando o caminho não está 100% claro. Mas há ainda mais a considerar:
- tamanho dos arquivos de log de transações
- tempo necessário para replicar (se estiver usando replicação)
- tempo que leva para ETL (se ETLing)
- tempo necessário para enviar logs para um sistema remoto e restaurar (se estiver usando o envio de logs)
- tamanho dos backups
- tempo necessário para concluir o backup
- tempo que leva para fazer uma restauração (isso pode ser importante um dia ;-)
- tamanho necessário para tempdb
- desempenho de gatilhos (para tabelas inseridas e excluídas armazenadas no tempdb)
- desempenho do controle de versão de linha (se estiver usando SNAPSHOT ISOLATION, já que o armazenamento de versão está no tempdb)
- capacidade de obter novo espaço em disco quando o CFO diz que gastou US $ 1 milhão em uma SAN no ano passado e, portanto, não autorizará outros US $ 250 mil para armazenamento adicional
- tempo necessário para executar as operações INSERT e UPDATE
- tempo necessário para fazer a manutenção do índice
- etc etc etc
A perda de espaço tem um enorme efeito cascata em todo o sistema. Eu escrevi um artigo entrando em detalhes explícitos sobre este tópico: O disco é barato! ORLY? (é necessário registro gratuito; desculpe-me por não controlar essa política).
Terceiro: enquanto algumas respostas estão incorretamente focadas no aspecto "este é um aplicativo pequeno" e outras estão sugerindo corretamente "usar o que é apropriado", nenhuma das respostas forneceu orientações reais ao OP Um detalhe importante mencionado na pergunta é que esta é uma página da web da escola deles. Ótimo! Então, podemos sugerir que:
- Os campos para nomes de Alunos e / ou Faculdade provavelmente devem ser
NVARCHAR, pois, com o tempo, é cada vez mais provável que nomes de outras culturas sejam exibidos nesses locais.
- Mas para endereço e nomes de cidades? O objetivo do aplicativo não foi declarado (teria sido útil), mas assumindo que os registros de endereço, se houver, pertencem apenas a uma região geográfica específica (por exemplo, um único idioma / cultura) e, em seguida, use
VARCHARa Página de Código apropriada (que é determinado a partir do agrupamento do campo).
- Se o armazenamento de códigos ISO do estado e / ou país (não é necessário armazenar
INT/ TINYINTjá que os códigos ISO são de comprimento fixo, legíveis por humanos e padrão): use CHAR(2)para códigos de duas letras e CHAR(3)se estiver usando três códigos de letras. E considere usar um agrupamento binário como Latin1_General_100_BIN2.
- Se estiver armazenando códigos postais (por exemplo, CEP), use,
VARCHARpois é um padrão internacional nunca usar nenhuma letra fora de AZ. E sim, ainda use, VARCHARmesmo que apenas armazene códigos postais dos EUA e não INT, pois os códigos postais não são números, são cadeias de caracteres e alguns deles têm um "0" inicial. E considere usar um agrupamento binário como Latin1_General_100_BIN2.
- Se você estiver armazenando endereços de e-mail e / ou URLs, use os
NVARCHARdois agora que podem conter caracteres Unicode.
- e assim por diante....
Quarto: agora que você tem NVARCHARdados que ocupam o dobro do espaço necessário para dados que se encaixam perfeitamente VARCHAR("se encaixa perfeitamente" = não se transforma em "?") E, de alguma forma, como por mágica, o aplicativo cresceu e agora existem milhões de registros em pelo menos um desses campos em que a maioria das linhas é ASCII padrão, mas algumas contêm caracteres Unicode, portanto, você deve mantê- las NVARCHAR, considere o seguinte:
Se você estiver usando o SQL Server 2008 - 2016 RTM e estiver no Enterprise Edition, OU se estiver usando o SQL Server 2016 SP1 (que disponibilizou a compactação de dados em todas as edições) ou mais recente, poderá habilitar a compactação de dados . A compactação de dados pode (mas não "sempre") compactar dados NCHARe NVARCHARcampos Unicode . Os fatores determinantes são:
NCHAR(1 - 4000)e NVARCHAR(1 - 4000)use o Esquema de compactação padrão para Unicode , mas apenas iniciando no SQL Server 2008 R2 E somente para dados IN ROW, não SOB FLUXO! Parece ser melhor que o algoritmo de compactação ROW / PAGE comum.
NVARCHAR(MAX)e XML(e acho que também VARBINARY(MAX), TEXTe NTEXT) dados que estão IN ROW (não fora da linha nas páginas LOB ou OVERFLOW) podem pelo menos ser compactados em PAGE, mas não compactados em ROW. Obviamente, a compactação PAGE depende do tamanho do valor em linha: testei com VARCHAR (MAX) e vi que as linhas de 6000 caracteres / byte não seriam compactadas, mas sim as linhas de 4000 caracteres / byte.
- Quaisquer dados OFF ROW, LOB ou OVERLOW = sem compressão para você!
Se você estiver usando o SQL Server 2005 ou 2008 - 2016 RTM e não no Enterprise Edition, poderá ter dois campos: um VARCHARe um NVARCHAR. Por exemplo, digamos que você esteja armazenando URLs que são na sua maioria caracteres ASCII básicos (valores de 0 a 127) e, portanto, se encaixam VARCHAR, mas às vezes têm caracteres Unicode. Seu esquema pode incluir os seguintes 3 campos:
...
URLa VARCHAR(2048) NULL,
URLu NVARCHAR(2048) NULL,
URL AS (ISNULL(CONVERT(NVARCHAR([URLa])), [URLu])),
CONSTRAINT [CK_TableName_OneUrlMax] CHECK (
([URLa] IS NOT NULL OR [URLu] IS NOT NULL)
AND ([URLa] IS NULL OR [URLu] IS NULL))
);
Neste modelo, você seleciona apenas a partir da [URL]coluna computada. Para inserir e atualizar, você determina qual campo usar, verificando se a conversão altera o valor recebido, que deve ser do NVARCHARtipo:
INSERT INTO TableName (..., URLa, URLu)
VALUES (...,
IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL),
IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL)
);
Você pode GZIP inserir valores VARBINARY(MAX)e descompactar na saída:
- Para o SQL Server 2005 - 2014: você pode usar o SQLCLR. SQL # (uma biblioteca SQLCLR que escrevi) vem com Util_GZip e Util_GUnzip na versão gratuita
- Para o SQL Server 2016 e mais recente: você pode usar o built-in
COMPRESSe DECOMPRESSfunções, que também são GZip.
Se você estiver usando o SQL Server 2017 ou mais recente, poderá transformar a tabela em um Índice de armazenamento de colunas em cluster.
Embora essa ainda não seja uma opção viável, o SQL Server 2019 apresenta suporte nativo para UTF-8 em VARCHAR/ CHARtipos de dados. Atualmente, existem muitos bugs com ele para serem usados, mas se forem corrigidos, essa é uma opção para alguns cenários. Consulte a minha publicação, " Suporte nativo a UTF-8 no SQL Server 2019: Salvador ou Falso Profeta? ", Para uma análise detalhada desse novo recurso.