Создание пользовательского типа, определенного пользователем, через SQLCLR - это , а не , в любом случае, вы получите замену любого собственного типа. Это очень удобно для создания чего-то для обработки специализированных данных. Но строки, даже другой кодировки, далеко не специализированы. Путь по этому маршруту для ваших строковых данных разрушит любое удобство использования вашей системы, не говоря уже о производительности, поскольку вы не сможете использовать любые встроенные строковые функции.
Если бы вы смогли сохранить что-либо на диске, эти выгоды были бы стерты из-за потери общей производительности. Хранение UDT осуществляется путем сериализации его в VARBINARY
. Таким образом, чтобы выполнить любое сравнение строк ИЛИ сортировку вне «двоичного» / «порядкового» сравнения, вам придется преобразовать все остальные значения, одно за другим, обратно в UTF-8, чтобы затем выполнить сравнение строк, которое может учитывать языковые различия. И это преобразование должно быть сделано в рамках UDT. Это означает, что, как и тип данных XML, вы должны создать UDT для хранения определенного значения, а затем предоставить метод этого UDT для принятия строкового параметра для сравнения (т. Е. Utf8String.Compare(alias.field1)
или, если определите оператор для введите Utf8string1 = Utf8string2
, и оператор =
получит строку в кодировке UTF-8, а затем выполните команду CompareInfo.Compare()
).
В дополнение к вышеприведенным соображениям вам также необходимо учитывать, что передача значений назад и вперед через API SQLCLR имеет свою стоимость, особенно при использовании NVARCHAR(MAX)
или VARBINARY(MAX)
вместо NVARCHAR(1 - 4000)
и VARBINARY(1 - 4000)
соответственно (пожалуйста, не путайте это различие с намеками на использование SqlChars
/ SqlBytes
против SqlString
/ SqlBinary
).
Наконец (по крайней мере, с точки зрения использования UDT), пожалуйста, не забывайте о том факте, что запрашиваемый UDT - это пример кода . Единственное отмеченное тестирование является чисто функциональным, ничего не касается масштабируемости или «уроков, извлеченных после работы с ним в течение года». Код функционального теста показан здесь на следующей странице CodePlex, и перед тем, как приступить к принятию этого решения, его следует рассмотреть, поскольку он дает представление о том, как вам нужно написать свои запросы для взаимодействия с ним (что хорошо для поля или два, но не для большинства / всех строковых полей):
http://msftengprodsamples.codeplex.com/SourceControl/latest#Kilimanjaro_Trunk/Programmability/CLR/UTF8String/Scripts/Test.sql
Учитывая количество сохраненных вычисляемых столбцов и добавленных индексов, действительно ли было сохранено какое-либо пространство? ; -)
Там, где пространство (диск, память и т. Д.) Является проблемой, у вас есть три варианта:
Если вы используете SQL Server 2008 или новее и используете Enterprise Edition, вы можете включить Сжатие данных . Сжатие данных может (но не всегда) сжимать данные Unicode в полях NCHAR
и NVARCHAR
. Определяющими факторами являются:
NCHAR(1 - 4000)
и NVARCHAR(1 - 4000)
используют стандартную схему сжатия для Unicode , но только начиная с SQL Server 2008 R2, И только для данных IN ROW, а не OVERFLOW! Это выглядит лучше, чем обычный алгоритм сжатия ROW / PAGE.
NVARCHAR(MAX)
и XML
(и, я думаю, также VARBINARY(MAX)
, TEXT
и NTEXT
) данные, которые находятся в строке (не в строке на страницах LOB или OVERFLOW), могут быть сжаты по крайней мере на странице, и возможно также ROW сжатый (не уверен насчет последнего).
- Любые данные OFF ROW, LOB или OVERLOW = Нет сжатия для вас!
Если вы используете версию более раннюю, чем 2008, или нет в Enterprise Edition, у вас может быть два поля: одно VARCHAR
и одно NVARCHAR
. Например, предположим, что вы храните URL-адреса, которые в основном все являются базовыми символами ASCII (значения 0–127) и, следовательно, вписываются в VARCHAR
, но иногда содержат символы Unicode. Ваша схема может включать следующие 3 поля:
...
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))
);
В этой модели вы только ВЫБЕРИТЕ из вычисляемого столбца [URL]
. Для вставки и обновления вы определяете, какое поле использовать, видя, изменяет ли преобразование входящее значение, которое должно иметь тип NVARCHAR
:
INSERT INTO TableName (..., URLa, URLu)
VALUES (...,
IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL),
IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL)
);
Если у вас есть поля, в которых должны быть только символы, которые вписываются в определенную кодовую страницу расширенного набора символов ASCII, просто используйте VARCHAR
.
PS Просто для ясности: новые _SC
параметры сортировки, которые были введены в SQL Server 2012, просто позволяют:
- встроенные функции для правильной обработки дополнительных символов / суррогатаПары и
- лингвистические правила для дополнительных символов, которые используются для упорядочения и сравнения
Но даже без новых сопоставлений _SC
вы все равно можете сохранить любой символ Unicode вТип с префиксом XML или N
и извлечение его без потери данных.Однако при использовании более старых сопоставлений (т.е. без номера версии в имени) все дополнительные символы приравниваются друг к другу.Вам нужно использовать параметры сортировки _90
и _100
, которые, по крайней мере, позволят вам сравнивать и сортировать двоичные / кодовые точки;они не могут принимать во внимание лингвистические правила, поскольку не имеют конкретных отображений дополнительных символов (и, следовательно, не имеют весов или правил нормализации).
Попробуйте выполнить следующее:
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'?';
ВБД, имеющая сопоставление по умолчанию, оканчивающееся на _SC
, только первый оператор IF
вернет набор результатов, а поле "Сгенерированный" будет правильно отображать символы.
Но, если БД неимеют параметры сортировки по умолчанию, оканчивающиеся на _SC
, и параметры сортировки не являются последовательностями сортировки _90
или _100
, тогда первые два оператора IF
возвращают наборы результатов, в которых поле "Сгенерировано" возвращает NULL
, иполе «Literal» отображается правильно.
Для данных Unicode сортировка не имеет отношения к физической памяти.
ОБНОВЛЕНИЕ 2018-10-02
Хотя этот вариант пока не подходит, в SQL Server 2019 появилась встроенная поддержка UTF-8 в типах данных VARCHAR
/ CHAR
.В настоящее время в нем слишком много ошибок, чтобы его можно было использовать, но если они исправлены, то это вариант для некоторых сценариев.Пожалуйста, смотрите мой пост " Собственная поддержка UTF-8 в SQL Server 2019: Спаситель или Лжепророк? " для подробного анализа этой новой функции.