Quais são as principais diferenças de desempenho entre os tipos de dados varchar e nvarchar do SQL Server?

Eu estou trabalhando em um database para um pequeno aplicativo da web na minha escola usando o SQL Server 2005 .
Eu vejo algumas escolas de pensamento sobre a questão do varchar vs nvarchar :

  1. Use varchar menos que você lide com muitos dados internacionalizados e use nvarchar .
  2. Apenas use nvarchar para tudo.

Eu estou começando a ver os méritos da visão 2. Eu sei que o nvarchar ocupa o dobro do espaço, mas isso não é necessariamente um grande negócio, já que isso só vai armazenar dados para algumas centenas de estudantes. Para mim, parece que seria mais fácil não se preocupar com isso e permitir que tudo usasse o nvarchar. Ou há algo que estou perdendo?

Sempre use nvarchar.

Você pode nunca precisar dos caracteres de byte duplo para a maioria dos aplicativos. No entanto, se você precisar oferecer suporte a idiomas de byte duplo e tiver suporte de byte único em seu esquema de database, será muito caro voltar e modificar todo o seu aplicativo.

O custo de migrar um aplicativo de varchar para nvarchar será muito mais do que o pouco de espaço extra em disco que você usará na maioria dos aplicativos.

Espaço em disco não é o problema … mas a memory e o desempenho serão. O dobro da página lê, tamanho de índice duplo, estranho LIKE e = comportamento constante etc.

Você precisa armazenar script chinês etc? Sim ou não…

E do MS BOL ” Efeitos de armazenamento e desempenho do Unicode ”

Editar :

Recente SO pergunta destacando o quão ruim o desempenho nvarchar pode ser …

SQL Server usa alta CPU ao pesquisar dentro de seqüências nvarchar

Ser consistente! JOIN-ing um VARCHAR para NVARCHAR tem um grande impacto no desempenho.

O nvarchar terá uma sobrecarga significativa em memory, armazenamento, conjunto de trabalho e indexação, portanto, se as especificações indicarem que isso realmente nunca será necessário, não se incomode.

Eu não teria uma regra dura e rápida “sempre nvarchar” porque pode ser um desperdício completo em muitas situações – particularmente ETL de ASCII / EBCDIC ou identificadores e colunas de código que geralmente são chaves e foreign keys.

Por outro lado, há muitos casos de colunas, onde eu teria certeza de fazer essa pergunta cedo e se eu não recebesse uma resposta rápida e dura imediatamente, eu faria a coluna nvarchar.

Para o seu aplicativo, nvarchar é bom porque o tamanho do database é pequeno. Dizer “use sempre nvarchar” é uma grande simplificação. Se você não é obrigado a armazenar coisas como Kanji ou outros personagens malucos, use VARCHAR, ele vai usar muito menos espaço. Meu antecessor no meu trabalho atual projetou algo usando o NVARCHAR quando não era necessário. Nós recentemente mudamos para VARCHAR e economizamos 15 GB apenas nessa tabela (foi muito bem escrito). Além disso, se você tiver um índice nessa tabela e quiser include essa coluna ou criar um índice composto, acabou aumentando o tamanho do arquivo de índice.

Apenas seja atencioso em sua decisão; no desenvolvimento de SQL e nas definições de dados, raramente parece haver uma “resposta padrão” (além de evitar cursores a todo custo, é claro).

Hesito em acrescentar mais uma resposta aqui, pois já existem algumas, mas alguns pontos precisam ser feitos que não foram feitos ou não foram feitos claramente.

Primeiro: não use sempre NVARCHAR . Essa é uma atitude / abordagem muito perigosa e muitas vezes cara. E não é melhor dizer ” Nunca use cursores”, pois eles são, às vezes, o meio mais eficiente de resolver um problema específico, e a solução comum de fazer um loop WHILE quase sempre será mais lenta que um Cursor feito corretamente .

A única vez que você deve usar o termo “sempre” é quando aconselha a “sempre fazer o que é melhor para a situação”. É bem difícil determinar, especialmente quando se tenta equilibrar ganhos de curto prazo em tempo de desenvolvimento (gerente: “precisamos desse recurso – que você não conhecia até agora – há uma semana!”) Com muito tempo custos de manutenção a curto prazo (gerente que inicialmente pressionou a equipe a concluir um projeto de 3 meses em uma corrida de 3 semanas: “por que estamos tendo esses problemas de desempenho? Como poderíamos ter feito o X que não tem flexibilidade? Não podemos pagar um sprint ou dois para consertar isso. O que podemos fazer em uma semana para que possamos voltar aos nossos itens prioritários? E nós 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 certas decisões de modelagem de dados quando o caminho não estiver 100% claro. Mas ainda há mais a considerar:

  • tamanho dos arquivos de log de transactions
  • tempo que leva para replicar (se estiver usando replicação)
  • tempo que leva para ETL (se ETLing)
  • tempo que leva para enviar logs para um sistema remoto e restaurar (se estiver usando Log Shipping)
  • tamanho dos backups
  • o tempo necessário para concluir o backup
  • tempo que leva para fazer uma restauração (isso pode ser importante algum dia 😉
  • tamanho necessário para tempdb
  • desempenho de gatilhos (para tabelas inseridas e excluídas armazenadas em tempdb)
  • desempenho do version control de linha (se estiver usando SNAPSHOT ISOLATION, desde que o armazenamento de versão esteja em tempdb)
  • capacidade de obter novo espaço em disco quando o CFO diz que acabou de gastar US $ 1 milhão em uma SAN no ano passado e, portanto, não autorizará outros US $ 250.000 para armazenamento adicional
  • o tempo necessário para executar operações INSERT e UPDATE
  • o tempo que leva para fazer a manutenção do índice
  • etc, etc, etc.

Desperdiçar espaço tem um enorme efeito cascata em todo o sistema. Eu escrevi um artigo que entrava em detalhes explícitos neste tópico: O disco é barato! ORLY (registro gratuito obrigatório; desculpe, eu não controle essa política).

Terceiro: Enquanto algumas respostas estão incorretamente focadas no aspecto “este é um pequeno aplicativo”, e algumas estão sugerindo corretamente “usar o que é apropriado”, nenhuma das respostas forneceu uma orientação real para o OP Um detalhe importante mencionado na Pergunta é que esta é uma página da web para a escola. Ótimo! Então podemos sugerir que:

  • Os campos para os nomes de alunos e / ou professores provavelmente devem ser NVARCHAR , pois, com o tempo, é mais provável que os nomes de outras culturas apareçam nesses locais.
  • Mas para endereços e nomes de cidades? O objective 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 (ou seja, um único idioma / cultura), use VARCHAR com a Página de código apropriada ( que é determinado a partir do agrupamento do campo).
  • Se estiver armazenando códigos ISO de estado e / ou país (não é necessário armazenar INT / TINYINT pois os códigos ISO são de tamanho fixo, legível e bem, padrão 🙂 use CHAR(2) para códigos de duas letras e CHAR(3) se usar 3 códigos de letras.
  • Se estiver armazenando códigos postais (ou seja, CEPs), use VARCHAR pois é um padrão internacional para nunca usar qualquer letra fora do AZ. E sim, ainda usar VARCHAR mesmo se apenas armazenar códigos postais dos EUA e não INT desde CEPs não são números, eles são seqüências de caracteres e alguns deles têm um “0” à esquerda.
  • Se estiver armazenando endereços de e-mail e / ou URLs, use o NVARCHAR pois ambos agora podem conter caracteres Unicode.
  • e assim por diante….

Quarto: Agora que você tem dados NVARCHAR ocupando o dobro do espaço necessário para dados que se encheckboxm perfeitamente em VARCHAR (“ajusta-se bem” = não se transforma em “?”) E de alguma forma, como por mágica, o aplicativo cresceu e agora há milhões de registros em pelo menos um desses campos em que a maioria das linhas são ASCII padrão, mas algumas contêm caracteres Unicode, portanto, você precisa manter NVARCHAR , considere o seguinte:

  1. Se você estiver usando o SQL Server 2008 ou mais recente e estiver no Enterprise Edition, poderá ativar a compactação de dados . A compactação de dados pode (mas não “sempre”) compactar dados Unicode nos campos NCHAR e NVARCHAR . Os fatores determinantes são:

    1. NCHAR(1 - 4000) e NVARCHAR(1 - 4000) usam o Esquema de Compactação Padrão para Unicode , mas apenas a partir do SQL Server 2008 R2, E somente para dados IN ROW, e não OVERFLOW! Isto parece ser melhor que o algoritmo de compression ROW / PAGE regular.
    2. NVARCHAR(MAX) e XML (e eu acho que também VARBINARY(MAX) , TEXT e NTEXT ) que estão IN ROW (não off row nas páginas LOB ou OVERFLOW) podem ser pelo menos PAGE compactados e talvez também ROW compactados (não certeza sobre este último).
    3. Qualquer dado de OFF ROW, LOB ou OVERLOW = No Compression For You!
  2. Se estiver usando uma versão anterior a 2008 ou não no Enterprise Edition, você poderá ter dois campos: um VARCHAR e um NVARCHAR . Por exemplo, digamos que você esteja armazenando URLs que são na maior parte todos os caracteres ASCII base (valores de 0 a 127) e, portanto, se encheckboxm em VARCHAR , mas às vezes têm caracteres Unicode. Seu esquema pode include os 3 campos a seguir:

      ... 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)) ); 

    Nesse modelo, você seleciona a partir da coluna computada [URL] . Para inserir e atualizar, você determina qual campo usar verificando se a conversão altera o valor de input, que deve ser do tipo NVARCHAR :

     INSERT INTO TableName (..., URLa, URLu) VALUES (..., IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL), IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL) ); 

Como o seu aplicativo é pequeno, não há praticamente nenhum aumento de custo apreciável no uso do nvarchar sobre o varchar, e você evita possíveis dores de cabeça no futuro, se tiver necessidade de armazenar dados unicode.

Nos últimos anos, todos os nossos projetos usaram o NVARCHAR para tudo, já que todos esses projetos são multilíngues. Os dados importados de fonts externas (por exemplo, um arquivo ASCII, etc.) são convertidos para Unicode antes de serem inseridos no database.

Eu ainda não encontrei nenhum problema relacionado ao desempenho dos índices maiores, etc. Os índices usam mais memory, mas a memory é barata.

Se você usa stored procedures ou constrói SQL rapidamente, assegure-se de que todas as constantes de string sejam prefixadas com N (por exemplo, SET @foo = N’Hello world. ‘;), Portanto a constante também é Unicode. Isso evita qualquer conversão de tipo de string no tempo de execução.

YMMV.

De um modo geral; Comece com o tipo de dados mais caro que tenha menos restrições. Coloque em produção . Se o desempenho começar a ser um problema, descubra o que está realmente sendo armazenado nessas colunas nvarchar . Existe algum personagem lá que não se encheckboxria no varchar ? Caso contrário, mude para varchar. Não tente pré-otimizar antes de saber onde está a dor. Meu palpite é que a escolha entre nvarchar / varchar não é o que vai retardar sua aplicação no futuro previsível. Haverá outras partes do aplicativo onde o ajuste de desempenho lhe dará muito mais retorno para os dólares .

Eu posso falar por experiência sobre isso, cuidado com o nvarchar . A menos que seja absolutamente necessário, esse tipo de campo de dados destrói o desempenho em um database maior. Eu herdei um database que estava doendo em termos de desempenho e espaço. Conseguimos reduzir em 70% o tamanho de um database de 30 GB! Houve algumas outras modificações feitas para ajudar com o desempenho, mas tenho certeza que o varchar ajudou significativamente com isso também. Se o seu database tiver o potencial de aumentar as tabelas para um milhão de registros, fique longe do nvarchar a todo custo.

Eu lido com essa questão no trabalho com frequência:

  • FTP feeds de estoque e preços – Descrições de itens e outros textos estavam em nvarchar quando varchar funcionava bem. Convertê-los para varchar reduziu o tamanho do arquivo quase pela metade e realmente ajudou nos uploads.

  • O cenário acima funcionou bem até que alguém colocou um caractere especial na descrição do item (talvez marca registrada, não lembro)

Eu ainda não uso nvarchar toda vez que varchar. Se houver alguma dúvida ou potencial para caracteres especiais, eu uso o nvarchar. Eu acho que eu uso varchar principalmente quando estou em 100% de controle do que está preenchendo o campo.

Por que, em toda essa discussão, não houve menção ao UTF-8? Ser capaz de armazenar o intervalo unicode completo de caracteres não significa que um deve sempre alocar dois bytes por caractere (ou “ponto de código” para usar o termo UNICODE). Todo o ASCII é UTF-8. O SQL Server verifica os campos VARCHAR () que o texto é estrito ASCII (ou seja, o bit de byte superior zero)? Eu espero que não.

Se, então, você quiser armazenar unicode e desejar compatibilidade com aplicativos mais antigos baseados em ASCII, eu pensaria que usar VARCHAR () e UTF-8 seria a mágica: Ele usa apenas mais espaço quando precisa.

Para aqueles que não estão familiarizados com o UTF-8, recomendo uma cartilha .

Haverá instâncias excepcionais quando você desejar restringir deliberadamente o tipo de dados para garantir que ele não contenha caracteres de um determinado conjunto. Por exemplo, eu tive um cenário em que precisava armazenar o nome de domínio em um database. A internacionalização de nomes de domínio não era confiável na época, portanto, era melhor restringir a input no nível básico e ajudar a evitar possíveis problemas.

Se você estiver usando NVARCHAR apenas porque um procedimento armazenado do sistema o requer, a ocorrência mais freqüente sendo inexplicavelmente sp_executesql , e sua SQL dinâmica for muito longa, seria melhor ter uma perspectiva de desempenho fazendo todas as manipulações de strings (concatenação, substituição etc.) VARCHAR então convertendo o resultado final para NVARCHAR e alimentando-o no parâmetro proc. Então não, nem sempre use NVARCHAR !

Intereting Posts