Criar um tipo definido pelo usuário personalizado via SQLCLR não , de qualquer forma, vai te dar um substituto de qualquer tipo nativo. É muito útil para criar algo para lidar com dados especializados. Mas strings, mesmo de uma codificação diferente, estão longe de ser especializadas. Seguir esse caminho para seus dados de string destruiria qualquer quantidade de usabilidade do seu sistema, sem mencionar o desempenho, pois você não seria capaz de usar qualquer funções de string embutidas.
Se você pudesse economizar qualquer coisa no espaço em disco, esses ganhos seriam apagados pelo que você perderia no desempenho geral. Armazenar um UDT é feito serializando-o para um
VARBINARY
. Então, para fazer qualquer comparação de strings OU classificação, fora de uma comparação "binária" / "ordinal", você teria que converter todos os outros valores, um por um, de volta para UTF-8 para fazer a comparação de strings que pode levar em conta as diferenças linguísticas. E essa conversão precisaria ser feita dentro da UDT. Isso significa que, como o tipo de dados XML, você criaria o UDT para manter um valor específico e, em seguida, exporia um método desse UDT para aceitar um parâmetro de string para fazer a comparação (ou seja, Utf8String.Compare(alias.field1)
ou, se estiver definindo um operador para o tipo, então Utf8string1 = Utf8string2
e tenha o =
operador obtém a string na codificação UTF-8 e, em seguida, faz o CompareInfo.Compare()
). Além das considerações acima, você também precisa considerar que passar valores de um lado para o outro pela API SQLCLR tem um custo, especialmente ao usar
NVARCHAR(MAX)
ou VARBINARY(MAX)
ao contrário de NVARCHAR(1 - 4000)
e VARBINARY(1 - 4000)
respectivamente (por favor, não confunda esta distinção como implicando algo sobre o uso de SqlChars
/ SqlBytes
vs SqlString
/ SqlBinary
). Finalmente (pelo menos em termos de uso de um UDT), não ignore o fato de que o UDT que está sendo consultado é código de amostra . O único teste observado é puramente funcional, nada sobre escalabilidade ou "lições aprendidas depois de trabalhar com isso por um ano". O código de teste funcional é mostrado aqui na página do CodePlex a seguir e deve ser analisado antes de prosseguir com esta decisão, pois dá uma ideia de como você precisaria escrever suas consultas para interagir com ele (o que é bom para um campo ou dois, mas não para a maioria/todos os campos de string):
http://msftengprodsamples.codeplex.com /SourceControl/latest#Kilimanjaro_Trunk/Programmability/CLR/UTF8String/Scripts/Test.sql
Dado o número de colunas e índices computados persistentes adicionados, algum espaço foi realmente economizado?;-)
Onde o espaço (disco, memória, etc) é a preocupação, você tem três opções:
-
Se você estiver usando o SQL Server 2008 ou mais recente e estiver no Enterprise Edition, poderá habilitar Compressão de dados . A compactação de dados pode (mas não "sempre") compactar dados Unicode emNCHAR
eNVARCHAR
Campos. Os fatores determinantes são:
NCHAR(1 - 4000)
eNVARCHAR(1 - 4000)
use o esquema de compactação padrão para Unicode , mas apenas a partir do SQL Server 2008 R2, E apenas para dados IN ROW, não OVERFLOW! Isso parece ser melhor do que o algoritmo de compactação ROW/PAGE normal.NVARCHAR(MAX)
eXML
(e acho que tambémVARBINARY(MAX)
,TEXT
eNTEXT
) os dados IN ROW (não fora da linha nas páginas LOB ou OVERFLOW) podem ser compactados pelo menos PAGE e talvez também ROW compactado (não tenho certeza sobre este último).- Quaisquer dados OFF ROW, LOB ou OVERLOW =Sem compactação para você!
-
Se estiver usando uma versão anterior a 2008 ou não na Enterprise Edition, você poderá ter dois campos:umVARCHAR
e umNVARCHAR
. Por exemplo, digamos que você está armazenando URLs que são principalmente todos os caracteres ASCII básicos (valores 0 - 127) e, portanto, se encaixam emVARCHAR
, mas às vezes têm caracteres Unicode. Seu esquema pode incluir 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)) );
Neste modelo você somente SELECIONE no[URL]
coluna computada. Para inserir e atualizar, você determina qual campo usar vendo se a conversão altera o valor de entrada, que deve ser deNVARCHAR
modelo:
INSERT INTO TableName (..., URLa, URLu) VALUES (..., IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL), IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL) );
-
Se você tiver campos que devem ter apenas caracteres que se encaixem em uma página de código específica de um conjunto de caracteres ASCII estendido, useVARCHAR
.
P.S. Apenas para esclarecer isso:o novo
_SC
Os agrupamentos que foram introduzidos no SQL Server 2012 simplesmente permitem:- as funções integradas para lidar adequadamente com os caracteres suplementares/pares substitutos e
- regras linguísticas para caracteres suplementares que são usados para ordenação e comparações
Mas, mesmo sem o novo
_SC
Collations, você ainda pode armazenar qualquer caractere Unicode em um XML ou N
-tipo prefixado e recuperá-lo sem perda de dados. No entanto, ao usar os agrupamentos mais antigos (ou seja, sem número de versão no nome), todos os caracteres suplementares se equivalem. Você precisa usar o _90
e _100
Agrupamentos que, pelo menos, fornecem comparações e classificação de pontos de código / binários; eles não podem levar em conta as regras linguísticas, pois não possuem mapeamentos específicos dos caracteres suplementares (e, portanto, não possuem pesos ou regras de normalização). Tente o seguinte:
IF (N'𤪆' = N'𤪆') SELECT N'𤪆' AS [TheLiteral], NCHAR(150150) AS [Generated];
IF (N'𤪆' = N'𤪇') SELECT N'𤪇' AS [TheLiteral], NCHAR(150151) AS [Generated];
IF (N'𤪆' COLLATE Tatar_90_CI_AI = N'𤪇' COLLATE Tatar_90_CI_AI)
SELECT N'𤪇 COLLATE Tatar_90_CI_AI' AS [TheLiteral], NCHAR(150151) AS [Generated];
IF (N'𤪆' = N'?') SELECT N'?';
Em um banco de dados com um agrupamento padrão terminando em
_SC
, apenas o primeiro IF
A instrução retornará um conjunto de resultados e o campo "Gerado" mostrará os caracteres corretamente. Mas, se o banco de dados não tiver um agrupamento padrão terminando em
_SC
, e o agrupamento não é um _90
ou _100
agrupamento de séries, então os dois primeiros IF
instruções retornam conjuntos de resultados em que o campo "Gerado" retornará NULL
, e o campo "Literal" aparece corretamente. Para dados Unicode, o Collation não afeta o armazenamento físico.
ATUALIZAÇÃO 2018-10-02
Embora 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. Existem atualmente muitos bugs com ele para ser usado, mas se eles forem corrigidos, então esta é uma opção para alguns cenários. Por favor, veja minha postagem, "Suporte UTF-8 nativo no SQL Server 2019:Salvador ou Falso Profeta?
", para uma análise detalhada desta nova funcionalidade.