Unicode в SQL Server: символы, байты и потеря текста
Выбирайте Unicode-хранение, учитывайте ограничения nvarchar и UTF-8 и проверяйте полный путь текста через приложение и базу.
Изменение столбца на nvarchar не восстановит текст, превращённый в вопросительные знаки до вставки. Корректность Unicode относится ко всему пути: декодирование источника, приложение, параметры драйвера, SQL-выражения, хранение и экспорт должны сохранять одинаковые символы.
Символы и размер хранения
В nvarchar(n) величина n обозначает пары байтов UTF-16, а не гарантированное число видимых символов. Дополнительный символ может занимать две единицы. Видимый знак также может состоять из нескольких кодовых точек, например буквы и комбинируемого акцента. Поэтому визуальный лимит приложения и лимит базы могут различаться.
DECLARE @text nvarchar(20)=N'café ';
SELECT LEN(@text) AS LengthWithoutTrailingSpaces,
DATALENGTH(@text) AS StorageBytes;
DECLARE @emoji nvarchar(2)=N'😀';
SELECT LEN(@emoji COLLATE Latin1_General_100_CI_AS_SC) AS Characters,
DATALENGTH(@emoji) AS StorageBytes;
Первое измерение показывает, что LEN игнорирует конечные пробелы, а DATALENGTH считает байты. Одного LEN недостаточно для точного сохранения текста. Второе измерение использует collation с поддержкой дополнительных символов: emoji считается одним символом, но занимает четыре байта nvarchar.
Префикс N создаёт Unicode-литерал. Без него преобразование через не-Unicode кодовую страницу может потерять символы ещё до присвоения nvarchar. Параметры приложения также должны явно использовать подходящий Unicode-тип. Проверяйте реальные нелатинские тексты, а не только ASCII-имена.
Осознанный выбор UTF-8
SQL Server 2019 поддерживает UTF-8 для varchar с соответствующей collation. Это не превращает все существующие varchar-столбцы в Unicode. Важны правила сравнения и промежуточные выражения. В varchar(n) величина n ограничивает байты, поэтому многобайтовые символы уменьшают доступное количество знаков.
UTF-8 может экономить место для преимущественно ASCII-текста; другим письменностям требуется больше байтов. Сравнивайте характерные значения и размеры индексов вместо предположения о гарантированной двукратной экономии. Учитывайте версию, ограничения столбцов и совместимость клиентов.
Изменение collation влияет и на уникальность. Сравнение без учёта регистра или акцентов может считать разные строки равными. Визуально одинаковые строки, наоборот, могут иметь разные последовательности кодовых точек. Явно определите нормализацию и правила идентичности.
Проверка полного маршрута
Подготовьте латинские акценты, кириллицу, CJK, emoji, комбинируемые знаки, кавычки и значимые конечные пробелы. Проведите их через настоящий API, параметризованную вставку, чтение, сериализацию и экспорт. Сравните возвращённую последовательность с оригиналом, а при необходимости и байты. Успешная вставка проверяет только один этап.
Перед миграцией измерьте максимальные байтовые длины и значения возле границы. Проверьте индексы, ограничения, вычисляемые поля и интеграции, всё ещё передающие varchar. Копия базы с проверкой полного возврата выявляет потери, невидимые по количеству строк.
Если старые данные уже содержат замены, найдите исходный источник. Смена типа не угадывает потерянный текст. Восстанавливайте его из проверенного источника или резервной копии и отмечайте записи, которые невозможно вернуть точно.
Цель состоит в возврате той же последовательности, кроме согласованной нормализации. Проверьте также скачивание и повторный импорт файла. Добавьте значения ровно на пределе и превышающие его, чтобы убедиться в явном отказе вместо молчаливого усечения. Отдельно сравните сообщения API и базы: пользователь должен получать согласованное объяснение ограничения. Если ограничения интерфейса считаются видимыми символами, тестируйте комбинируемые последовательности отдельно от обычных букв. Драйвер, кодирование файла и промежуточные преобразования важны не меньше определения столбца.
При смене collation отдельно сравните сортировку и существующие уникальные ключи. Успешное преобразование текста не доказывает, что прежние различные значения останутся различными для нового сравнения. Найдите возможные конфликты до изменения рабочего индекса.
Техническая документация: Microsoft Learn: nvarchar · Microsoft Learn: Unicode and UTF-8 · Microsoft Learn: DATALENGTH.