Каковы основные различия в производительности между типами данных SQL Server varchar и nvarchar? - PullRequest
230 голосов
/ 30 августа 2008

Я работаю над базой данных для небольшого веб-приложения в моей школе, используя SQL Server 2005.
Я вижу пару школ мысли по вопросу varchar против nvarchar:

  1. Используйте varchar, если вы не имеете дело с большим количеством интернационализированных данных, затем используйте nvarchar.
  2. Просто используйте nvarchar для всего.

Я начинаю видеть достоинства представления 2. Я знаю, что nvarchar занимает вдвое больше места, но это не обязательно огромная сделка, так как она собирается хранить данные только для нескольких сотен студентов. Мне кажется, что было бы проще не беспокоиться об этом и просто позволить всему использовать nvarchar. Или мне чего-то не хватает?

Ответы [ 14 ]

220 голосов
/ 13 октября 2008

Дисковое пространство не проблема ... но память и производительность будут. Двойное чтение страниц, двойной размер индекса, странное LIKE и = постоянное поведение и т. Д.

Вам нужно хранить китайский сценарий и т. Д.? Да или нет ...

И от MS BOL " Хранение и производительность Unicode "

Редактировать

Недавний вопрос о том, насколько плохой может быть производительность nvarchar ...

SQL Server использует высокий ЦП при поиске внутри строк nvarchar

143 голосов
/ 30 августа 2008

Всегда используйте nvarchar.

Для большинства приложений вам никогда не понадобятся двухбайтовые символы. Однако, если вам требуется поддержка двухбайтовых языков и в вашей схеме базы данных есть только однобайтовая поддержка, будет очень дорого вернуться и модифицировать свое приложение.

Стоимость переноса одного приложения из varchar в nvarchar будет намного больше, чем немного дополнительного дискового пространства, которое вы будете использовать в большинстве приложений.

60 голосов
/ 31 октября 2008

Будьте последовательны! Присоединение VARCHAR к NVARCHAR имеет большой успех.

41 голосов
/ 31 октября 2008

nvarchar будет иметь значительные накладные расходы в памяти, хранилище, рабочем наборе и индексации, поэтому, если спецификации диктуют, что он действительно никогда не понадобится, не беспокойтесь.

У меня не было бы жесткого и быстрого правила "всегда nvarchar", потому что оно может быть полной тратой во многих ситуациях - особенно ETL из ASCII / EBCDIC или идентификаторы и столбцы кода, которые часто являются ключами и внешними ключами.

С другой стороны, существует множество случаев столбцов, в которых я обязательно задал бы этот вопрос рано, и если бы я не получил быстрого и быстрого ответа, я бы сделал столбец nvarchar.

21 голосов
/ 30 января 2009

Для вашего приложения nvarchar подходит, потому что размер базы данных небольшой. Сказать «всегда используйте nvarchar» - это чрезмерное упрощение. Если вам не нужно хранить такие вещи, как кандзи или другие сумасшедшие персонажи, используйте VARCHAR, это займет намного меньше места. Мой предшественник на моей нынешней работе разработал что-то, используя NVARCHAR, когда это было не нужно. Недавно мы переключили его на VARCHAR и сэкономили 15 ГБ только на этой таблице (это было очень записано). Кроме того, если у вас есть индекс для этой таблицы, и вы хотите включить этот столбец или создать составной индекс, вы просто увеличили размер файла индекса.

Просто будьте внимательны в своем решении; в разработке SQL и определениях данных, похоже, редко встречается «ответ по умолчанию» (конечно, кроме обхода курсоров любой ценой).

16 голосов
/ 30 сентября 2015

Я не решаюсь добавить еще один ответ здесь, поскольку их уже немало, но необходимо сделать несколько замечаний, которые либо не были сделаны, либо не были сделаны четко.

Первый: Делать Не всегда использовать NVARCHAR. Это очень опасный и часто дорогостоящий подход / подход. И не лучше сказать « Никогда использовать курсоры», поскольку они иногда являются наиболее эффективным средством решения конкретной проблемы, и общий обходной цикл WHILE почти всегда будет медленнее чем правильно готово Курсор.

Единственный раз, когда вы должны использовать термин «всегда», это когда вы советуете «всегда делать то, что лучше для ситуации». Конечно, это часто трудно определить, особенно когда мы пытаемся сбалансировать краткосрочные выгоды во времени разработки (менеджер: «нам нужна эта функция, о которой вы не знали до сих пор - неделю назад!») С давно расходы на техническое обслуживание (менеджер, который первоначально заставил команду завершить трехмесячный проект в трехнедельном спринте: «почему у нас возникают такие проблемы с производительностью? как мы могли бы сделать X, у которого нет гибкости? один-два спринта, чтобы это исправить. Что мы можем сделать за неделю, чтобы вернуться к приоритетным задачам? И нам определенно нужно больше времени уделять дизайну, чтобы этого не происходило! »).

Второе: @ Ответ gbn затрагивает некоторые очень важные моменты, которые следует учитывать при принятии определенных решений по моделированию данных, когда путь не ясен на 100%. Но есть еще что рассмотреть:

  • размер файлов журнала транзакций
  • время, необходимое для репликации (при использовании репликации)
  • время, необходимое для ETL (если ETLing)
  • время, необходимое для отправки журналов в удаленную систему и восстановления (если используется доставка журналов)
  • размер резервных копий
  • время, необходимое для завершения резервного копирования
  • длительность восстановления (это может быть важно когда-нибудь; -)
  • размер, необходимый для tempdb
  • производительность триггеров (для вставленных и удаленных таблиц, которые хранятся в базе данных tempdb)
  • производительность версионирования строк (если используется SNAPSHOT ISOLATION, поскольку хранилище версий находится в базе данных tempdb)
  • возможность получить новое дисковое пространство, когда финансовый директор говорит, что они только что потратили 1 миллион долларов на SAN в прошлом году, и поэтому они не будут выделять еще 250 тысяч долларов на дополнительное хранилище
  • длительность выполнения операций INSERT и UPDATE
  • время, необходимое для обслуживания индекса
  • и т. Д. И т. П.

Потеря пространства имеет огромный каскадный эффект на всю систему. Я написал статью, подробно описав эту тему: Диск дешев! ORLY? (требуется бесплатная регистрация; извините, я не контролирую эту политику).

Третье: Хотя некоторые ответы неправильно фокусируются на аспекте «это маленькое приложение», а некоторые правильно предлагают «использовать то, что подходит», ни один из ответов не дал реального руководства для ОП Важной деталью, упомянутой в Вопросе, является то, что это веб-страница для их школы. Большой! Таким образом, мы можем предложить, что:

  • Поля для имен студентов и / или преподавателей должны , вероятно, быть NVARCHAR, поскольку со временем становится все более вероятным, что имена из других культур будут появляться в этих местах.
  • Но для адреса и названия города? Цель приложения не была указана (это было бы полезно), но при условии, что адресные записи, если таковые имеются, относятся только к определенному географическому региону (т. Е. К одному языку / культуре), затем используйте VARCHAR с соответствующим кодом Страница (которая определяется из сопоставления поля).
  • Если хранятся коды ISO штата и / или страны (не нужно хранить INT / TINYINT, поскольку коды ISO имеют фиксированную длину, удобочитаемы и, что ж, стандартны :), используйте CHAR(2) для двухбуквенных кодов и CHAR(3) при использовании трехбуквенных кодов. И подумайте об использовании двоичного сопоставления, такого как Latin1_General_100_BIN2.
  • При хранении почтовых индексов (то есть почтовых индексов) используйте VARCHAR, поскольку это международный стандарт, запрещающий использование букв за пределами A-Z. И да, по-прежнему используйте VARCHAR, даже если хранятся только почтовые индексы США, а не INT, поскольку почтовые индексы не являются числами, они являются строками, и некоторые из них имеют начальный «0». И рассмотрите возможность использования двоичной сортировки, такой как Latin1_General_100_BIN2.
  • При хранении адресов электронной почты и / или URL-адресов используйте NVARCHAR, поскольку теперь оба они могут содержать символы Юникода.
  • и т. Д.

Четвертый: Теперь, когда у вас есть NVARCHAR данные, занимающие вдвое больше места, чем нужно для данных, которые хорошо вписываются в VARCHAR ("хорошо вписывается" = не превращается в " ? ") и каким-то образом, как по волшебству, приложение действительно выросло, и теперь миллионы записей есть по крайней мере в одном из этих полей, где большинство строк являются стандартными ASCII, но некоторые содержат символы Юникода, поэтому вам придется сохранить NVARCHAR, учтите следующее:

  1. Если вы используете SQL Server 2008 - 2016 RTM и для Enterprise Edition, ИЛИ если вы используете SQL Server 2016 SP1 (который сделал сжатие данных доступным во всех выпусках) или новее, то вы можно включить Сжатие данных . Сжатие данных может (но не всегда) сжимать данные Unicode в полях NCHAR и NVARCHAR. Определяющими факторами являются:

    1. NCHAR(1 - 4000) и NVARCHAR(1 - 4000) используют стандартную схему сжатия для Unicode , но только начиная с SQL Server 2008 R2, И только для данных IN ROW, а не OVERFLOW! Это выглядит лучше, чем обычный алгоритм сжатия ROW / PAGE.
    2. NVARCHAR(MAX) и XML (и я предполагаю также, что VARBINARY(MAX), TEXT и NTEXT) данные, которые находятся в строке (не в строке на страницах LOB или OVERFLOW), по крайней мере, могут быть сжаты PAGE, но не ROW сжатый. Конечно, сжатие PAGE зависит от размера значения в строке: я протестировал VARCHAR (MAX) и увидел, что 6000 строк символов / байтов не будут сжиматься, а 4000 строк символов / байтов -
    3. Любые данные OFF ROW, LOB или OVERLOW = Нет сжатия для вас!
  2. При использовании SQL Server 2005 или RTM 2008 - 2016 и не в 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)
           );
    
  3. Вы можете записать входящие значения в VARBINARY(MAX) и затем разархивировать при выходе:

    • Для SQL Server 2005 - 2014: вы можете использовать SQLCLR. SQL # (библиотека SQLCLR, которую я написал) поставляется с Util_GZip и Util_GUnzip в бесплатной версии
    • Для SQL Server 2016 и новее: вы можете использовать встроенные функции COMPRESS и DECOMPRESS, которые также являются GZip.
  4. Если вы используете SQL Server 2017 или новее, вы можете сделать таблицу Clustered Columnstore Index.

  5. Хотя этот вариант пока не подходит, в SQL Server 2019 появилась встроенная поддержка UTF-8 в типах данных VARCHAR / CHAR. В настоящее время в нем слишком много ошибок, чтобы его можно было использовать, но если они исправлены, то это вариант для некоторых сценариев. Пожалуйста, смотрите мой пост " Собственная поддержка UTF-8 в SQL Server 2019: Спаситель или Лжепророк? " для подробного анализа этой новой функции.

10 голосов
/ 30 августа 2008

Поскольку ваше приложение небольшого размера, использование nvarchar вместо varchar существенно не увеличится, и вы избавите себя от возможных головных болей в будущем, если у вас возникнет необходимость в хранении данных Unicode.

8 голосов
/ 22 февраля 2013

Вообще говоря; Начните с самого дорогого типа данных, который имеет наименьшие ограничения. Запусти в производство . Если производительность начинает вызывать проблемы, выясните, что на самом деле хранится в этих nvarchar столбцах. Есть ли там персонажи, которые не вписываются в varchar? Если нет, переключитесь на varchar. Не пытайтесь предварительно оптимизировать, пока не узнаете, где боль. Я предполагаю, что выбор между nvarchar / varchar - это не то, что замедлит ваше приложение в обозримом будущем. Будут и другие части приложения, где настройка производительности даст вам гораздо больше ударов по долларам .

7 голосов
/ 04 апреля 2011

Я могу говорить по своему опыту, остерегайтесь nvarchar. Если это абсолютно не требуется, этот тип поля данных снижает производительность в большой базе данных. Я унаследовал базу данных, которая вредит производительности и пространству. Мы смогли уменьшить размер базы данных 30 ГБ на 70%! Были сделаны некоторые другие модификации, чтобы помочь с производительностью, но я уверен, что varchar также значительно помог с этим. Если в вашей базе данных есть потенциал для увеличения таблиц до миллиона записей, держитесь подальше от nvarchar любой ценой.

7 голосов
/ 30 января 2009

За последние несколько лет все наши проекты использовали NVARCHAR для всего, так как все эти проекты многоязычны. Импортированные данные из внешних источников (например, файл ASCII и т. Д.) Перед преобразованием в базу данных преобразуются в Unicode.

Мне еще не приходилось сталкиваться с проблемами, связанными с производительностью больших индексов и т. Д. Индексы используют больше памяти, но память дешевая.

Независимо от того, используете ли вы хранимые процедуры или создаете SQL на лету, убедитесь, что все строковые константы имеют префикс N (например, SET @foo = N'Hello world. ';), Поэтому константа также является Unicode. Это исключает любое преобразование строкового типа во время выполнения.

YMMV.

...