Quando o `nvarchar / nchar` será usado com o SQL Server 2019?

11

Com o SQL Server 2019 Microsoft introduz suporte UTF-8 para CHARe VARCHARtipos de dados e diz:

Esse recurso pode proporcionar economia significativa de armazenamento, dependendo do conjunto de caracteres em uso. Por exemplo, alterar um tipo de dados de coluna existente com cadeias ASCII de NCHAR (10) para CHAR (10) usando um agrupamento habilitado para UTF-8, se traduz em uma redução de quase 50% nos requisitos de armazenamento. Essa redução ocorre porque NCHAR (10) requer 22 bytes para armazenamento, enquanto CHAR (10) requer 12 bytes para a mesma cadeia Unicode.

O UTF-8 parece suportar todos os scripts, portanto, basicamente, podemos começar a armazenar dados Unicode em varchare charcolunas. E como é dito na documentação, isso pode reduzir o tamanho de tabelas e índices e, a partir daí, podemos obter um desempenho ainda melhor, porque uma quantidade menor de dados é lida.

Gostaria de saber se isso significa que podemos parar de usar nvarchare ncharcolunas que implementam UTF-16?

Alguém pode apontar um cenário e uma razão para não usar os tipos de dados char com UTFcodificação e continuar usando os n-chars?

gotqn
fonte
Por que você não testa e relata? Além disso, informe-nos quanto esforço você gastou para converter de nvarchar para varchar - quanto tempo as tabelas de alteração levaram, e quanto tempo você passou testando e quais problemas você encontrou.
Colin 'Hart Hart
@ Colin'tHart Se não houver problemas ou considerações conhecidas, planejo migrar os dados, pois acredito que a leitura de menos dados levará a um melhor desempenho do sistema. Sobre a conversão - levará tempo, é claro, especialmente se você tiver índices com a coluna especificada - eles precisam ser reconstruídos, mas acredito que valerá a pena. É claro que testarei em breve o impacto no desempenho, procurando apenas problemas que tornem a migração desnecessária.
gotqn
Observe que o SQL Server oferece suporte à compactação Unicode para colunas NVarchar ao usar a compactação PAGE ou ROW. docs.microsoft.com/en-us/sql/relational-databases/…
David Browne - Microsoft
11
Vale a pena notar que, embora o UTF-8 possa economizar espaço se você estiver armazenando "dados do tipo ASCII", não é compactação por si só e não deve ser confundido como tal. Por exemplo, se você estiver armazenando principalmente nomes chineses em um banco de dados, seria melhor usar CHARtipos UTF-8 do que tipos Unicode (com ou sem compactação, já que, em última análise, os dados precisam ser descompactados para serem processados). Considere também que o tipo de string nativo do Windows é Unicode, portanto, as strings UTF-8 geralmente precisam ser decodificadas. As compensações envolvidas significam que não é provável que os Ntipos sejam aposentados tão cedo.
Jeroen Mostert
11
O "aplicativo matador" nº 1 para UTF-8 CHARprovavelmente é o SQL Server no Linux, se o mecanismo obtiver suporte nativo para processar cadeias diretamente como UTF-8 - aqui UTF-8 é o conjunto de caracteres "nativo" (mais ou menos) e manter as cordas ao redor como UTF-16 é a alternativa menos eficiente. Também não vai doer usá-lo no Windows em locais onde você já está usando CHAR, é claro, já que agrupamentos que restringem os caracteres que podem ser armazenados nunca foram atraentes.
Jeroen Mostert

Respostas:

6

isso pode reduzir o tamanho de tabelas e índices (ênfase adicionada)

Redução no tamanho só é possível se a maioria dos personagens são essencialmente [space], 0 - 9, A - Z, a - z, e alguns sinais de pontuação básica. Fora desse conjunto específico de caracteres (em termos de uso prático, valores ASCII padrão 32 - 126), você terá, na melhor das hipóteses , tamanho igual a NVARCHAR/ UTF-16 ou, em muitos casos, maior.

Estou planejando migrar os dados, pois acredito que a leitura de menos dados levará a um melhor desempenho para o sistema.

Seja cuidadoso. O UTF-8 não é um interruptor mágico "conserte tudo". Todas as outras coisas são iguais, sim, ler menos melhora o desempenho. Mas aqui "todas as outras coisas" não são iguais. Mesmo ao armazenar apenas caracteres ASCII padrão (ou seja: todos os caracteres têm 1 byte, exigindo, portanto, metade do espaço em comparação com a armazenagem NVARCHAR), há uma pequena penalidade de desempenho ao usar UTF-8. Acredito que o problema se deva ao fato de o UTF-8 ser uma codificação de comprimento variável, o que significa que cada byte deve ser interpretado conforme é lido para saber se é um caractere completo ou se o próximo byte faz parte dele. Isso significa que todas as operações de cadeia precisam começar do início e prosseguir byte a byte. Por outro lado,NVARCHAR / UTF-16 é sempre 2 bytes (até caracteres suplementares são compostos por dois pontos de código de 2 bytes), para que tudo possa ser lido em blocos de 2 bytes.

Nos meus testes, mesmo com apenas caracteres ASCII padrão, o armazenamento dos dados como UTF-8 não proporcionou economia de tempo decorrido, mas foi definitivamente pior para o tempo da CPU. E isso sem a compactação de dados, pelo menos havia menos espaço em disco usado. Porém, ao usar a compactação, o espaço necessário para o UTF-8 era apenas 1% - 1,5% menor. Tão eficazmente, sem economia de espaço, quanto maior tempo de CPU para UTF-8.

As coisas ficam mais complicadas ao usar, NVARCHAR(MAX)pois a compactação Unicode não funciona com esse tipo de dados, mesmo que o valor seja pequeno o suficiente para ser armazenado em linha. Mas, se os dados forem pequenos o suficiente, eles ainda deverão se beneficiar da compactação de linha ou de página (nesse caso, eles realmente se tornam mais rápidos que o UTF-8). No entanto, dados fora da linha não podem usar nenhuma compactação. Ainda assim, tornar a tabela um Índice de armazenamento de colunas em cluster reduz bastante o tamanho de NVARCHAR(MAX)(mesmo que ainda seja um pouco maior que UTF-8 ao usar o Índice de armazenamento de colunas em cluster).

Alguém pode apontar um cenário e uma razão, para não usar os tipos de dados char com codificação UTF

Definitivamente. Na verdade, não acho realmente um motivo convincente para usá-lo na maioria dos casos. O único cenário que realmente se beneficia do UTF-8 é:

  1. Os dados são principalmente ASCII padrão (valores 0 - 127)
  2. Ele precisa ser Unicode, pois pode precisar armazenar um intervalo maior de caracteres do que o disponível em qualquer página de código de 8 bits (por exemplo VARCHAR)
  3. A maioria dos dados é armazenada fora da linha (portanto, a compactação de página nem funciona)
  4. Você tem dados suficientes para reduzir / reduzir o tamanho por motivos que não envolvem o desempenho da consulta (por exemplo, reduzir o tamanho do backup, reduzir o tempo necessário para fazer backup / restauração, etc.)
  5. Você não pode usar o Índice de armazenamento de colunas em cluster (talvez o uso da tabela torne o desempenho pior neste caso?)

Meus testes mostram que, em quase todos os casos, o NVARCHAR foi mais rápido, especialmente quando havia mais dados. De fato, 21k linhas com uma média de 5k caracteres por linha exigiam 165 MB para UTF-8 e 236 MB para NVARCHARdescompactado. E, no entanto, NVARCHARfoi duas vezes mais rápido no tempo decorrido e pelo menos duas vezes mais rápido (às vezes mais) no tempo da CPU. Ainda assim, foram necessários 71 MB a mais em disco.

Fora isso, eu ainda não recomendaria o uso de UTF-8, pelo menos a partir do CTP 2, devido a uma variedade de erros que encontrei nesse recurso.

Para uma análise detalhada desse novo recurso, incluindo uma explicação das diferenças entre UTF-16 e UTF-8 e uma lista desses erros, consulte o meu post:

Suporte nativo a UTF-8 no SQL Server 2019: Salvador ou Falso Profeta?

Solomon Rutzky
fonte
12

O suporte UTF-8 oferece um novo conjunto de opções. A economia potencial de espaço (sem compactação de linha ou página ) é uma consideração, mas a escolha do tipo e codificação provavelmente deve ser feita principalmente com base nos requisitos reais de comparação, classificação, importação de dados e exportação .

Pode ser necessário alterar mais do que você pensa, pois, por exemplo, um nchar(1)tipo fornece dois bytes de armazenamento. Isso é suficiente para armazenar qualquer caractere no BMP (pontos de código 000000 a 00FFFF). Alguns dos caracteres desse intervalo seriam codificados com apenas 1 byte em UTF-8, enquanto outros exigiriam 2 ou até 3 bytes (consulte esta tabela de comparação para obter mais detalhes). Portanto, seria necessário garantir a cobertura do mesmo conjunto de caracteres em UTF-8 char(3).

Por exemplo:

DECLARE @T AS table 
(
    n integer PRIMARY KEY,
    UTF16 nchar(1) COLLATE Latin1_General_CI_AS,
    UTF8 char(1) COLLATE Latin1_General_100_CI_AS_SC_UTF8
);

INSERT @T (n, UTF16, UTF8)
SELECT 911, NCHAR(911), NCHAR(911);

dá o erro familiar:

A mensagem 8152, nível 16, estado 30, linha xxx
String ou dados binários seria truncada.

Ou se o sinalizador de rastreamento 460 estiver ativo:

A mensagem 2628, nível 16, estado 1, linha xxx
String ou dados binários seria truncada na tabela '@T', coluna 'UTF8'. Valor truncado: ''.

Expandir a coluna UTF8 para char(2)ou varchar(2)resolver o erro de NCHAR(911):

DECLARE @T AS table 
(
    n integer PRIMARY KEY,
    UTF16 nchar(1) COLLATE Latin1_General_CI_AS,
    UTF8 varchar(2) COLLATE Latin1_General_100_CI_AS_SC_UTF8
);

INSERT @T (n, UTF16, UTF8)
SELECT 911, NCHAR(911), NCHAR(911);

No entanto, se fosse NCHAR(8364), por exemplo , você precisaria expandir ainda mais a coluna, para char(3)ou varchar(3).

Observe também que todos os agrupamentos UTF-8 usam caracteres suplementares, portanto não funcionarão com replicação.

Além de qualquer outra coisa, o suporte a UTF-8 está apenas em visualização no momento, portanto, não está disponível para uso em produção.

Paul White 9
fonte