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 WHILE
loop 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
VARCHAR
a 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
/ TINYINT
já 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,
VARCHAR
pois é um padrão internacional nunca usar nenhuma letra fora de AZ. E sim, ainda use, VARCHAR
mesmo 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
NVARCHAR
dois agora que podem conter caracteres Unicode.
- e assim por diante....
Quarto: agora que você tem NVARCHAR
dados 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 NCHAR
e NVARCHAR
campos 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)
, TEXT
e 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 VARCHAR
e 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 NVARCHAR
tipo:
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
COMPRESS
e DECOMPRESS
funçõ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
/ CHAR
tipos 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.