Каковы варианты использования для выбора CHAR вместо VARCHAR в SQL?

StackOverflow https://stackoverflow.com/questions/59667

  •  09-06-2019
  •  | 
  •  

Вопрос

Я понимаю, что CHAR рекомендуется использовать, если все мои значения имеют фиксированную ширину.Но что с того?Почему бы просто не выбрать VARCHAR для всех текстовых полей на всякий случай.

Это было полезно?

Решение

Обычно выбирают ОБУГЛИВАЮЩИЙСЯ если все строки будут иметь значение, близкое к такой же длины.Выбирай VARCHAR ( ПЕРЕМЕННЫЙ ) когда длина варьируется значительно.CHAR также может быть немного быстрее, потому что все строки имеют одинаковую длину.

Это зависит от реализации БД, но обычно VARCHAR использует еще один или два байта памяти (для длины или завершения) в дополнение к фактическим данным.Итак (предполагая, что вы используете однобайтовый набор символов), сохраняющий слово "FooBar".

  • CHAR(6) = 6 байт (без накладных расходов)
  • VARCHAR(10) = 8 байт (2 байта служебных данных)
  • CHAR(10) = 10 байт (4 байта служебных данных)

Суть в том, что ОБУГЛИВАЮЩИЙСЯ может быть быстрее и многое другое экономия пространства для данных относительно одинаковой длины (с разницей в два символа).

Примечание:Microsoft SQL имеет 2 байта служебных данных для VARCHAR.Это может варьироваться от базы данных к базе данных, но обычно для указания длины или EOL в VARCHAR требуется не менее 1 байта служебных данных.

Как было указано Гавеном в комментариях, если вы используете многобайтовый набор символов переменной длины, такой как UTF8, то CHAR хранит максимальное количество байтов, необходимое для хранения количества символов.Таким образом, если UTF8 требуется не более 3 байт для хранения символа, то CHAR(6) будет зафиксирован на уровне 18 байт, даже если хранятся только символы latin1.Так что в этом случае VARCHAR становится гораздо лучшим выбором.

Другие советы

Если вы работаете со мной и с Oracle, я бы, вероятно, заставил вас использовать varchar почти при любых обстоятельствах.Предположение о том , что char потребляет меньше вычислительной мощности, чем varchar может быть, это и правда ... на данный момент ... но движки баз данных со временем становятся лучше, и такого рода общее правило создает будущий "миф".

Еще кое - что:Я никогда не видел проблем с производительностью из-за того, что кто-то решил пойти с varchar.Вы гораздо лучше потратите свое время на написание хорошего кода (меньше обращений к базе данных) и эффективного SQL (как работают индексы, как оптимизатор принимает решения, почему exists быстрее, чем in обычно...).

Последняя мысль:Я видел всевозможные проблемы с использованием CHAR, люди, ищущие "когда они должны искать " ', или люди, ищущие "FOO", когда они должны искать "FOO (здесь куча пробелов)", или люди, не обрезающие конечные пробелы, или ошибки с Powerbuilder, добавляющие до 2000 пробелов к значению, которое он возвращает из процедуры Oracle.

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

Char работает немного быстрее, поэтому, если у вас есть столбец, который, как вы ЗНАЕТЕ, будет определенной длины, используйте char .Например, сохранение (M) ale / (F) emale / (U)nknown для обозначения пола или 2 символов для обозначения штата США.

Работают ли NChar или Char лучше, чем их альтернативы var?

Отличный вопрос.Простой ответ - да в определенных ситуациях.Давайте посмотрим, можно ли это объяснить.

Очевидно, мы все знаем, что если я создам таблицу со столбцом varchar(255) (назовем этот столбец MyColumn) и вставлю миллион строк, но добавлю только несколько символов в MyColumn для каждой строки, таблица будет намного меньше (общее количество страниц данных, необходимых механизму хранения), чем если бы я создал MyColumn как char(255).Всякий раз, когда я выполняю операцию (DML) над этой таблицей и запрашиваю много строк, это будет быстрее, когда MyColumn имеет значение varchar, потому что мне не нужно двигаться вокруг всех этих "лишних" пробелов в конце.Переместить, например, когда SQL Server выполняет внутреннюю сортировку, например, во время операции distinct или union, или если он выбирает слияние во время выполнения плана запроса и т.д.Перемещение также может означать время, необходимое для передачи данных с сервера на мой локальный компьютер, или на другой компьютер, или куда бы то ни было, где они будут использоваться.

Но при использовании varchar возникают некоторые накладные расходы.SQL Server должен использовать двухбайтовый индикатор (служебные данные), чтобы в каждой строке знать, сколько байт содержится в MyColumn этой конкретной строки.Проблема заключается не в дополнительных 2 байтах, а в необходимости "декодировать" длину данных в MyColumn в каждой строке.

По моему опыту, наиболее разумно использовать char вместо varchar для столбцов, к которым будут присоединяться запросы.Например, первичный ключ таблицы или какого-либо другого столбца, который будет проиндексирован.CustomerNumber в демографической таблице, или CodeID в таблице декодирования, или, возможно, OrderNumber в таблице заказов.Используя char , механизм запросов может быстрее выполнить объединение, потому что он может выполнять прямую арифметику указателей (детерминированно) вместо того, чтобы перемещать указатели на переменное количество байт при чтении страниц.Я знаю, что, возможно, упустил тебя из виду на последнем предложении.Объединения в SQL Server основаны на идее "предикатов". Предикат - это условие.Например, MyColumn = 1 или OrderNumber < 500.

Таким образом, если SQL Server выполняет инструкцию DML, а предикаты или "ключи", с которыми соединяются, имеют фиксированную длину (char), механизму запросов не нужно выполнять столько работы, чтобы сопоставить строки из одной таблицы со строками из другой таблицы.Ему не нужно будет выяснять, какой длины данные находятся в строке, а затем идти вниз по строке, чтобы найти конец.На все это требуется время.

Теперь имейте в виду, что это легко может быть плохо реализовано.Я видел, что символ char используется для полей первичного ключа в онлайн-системах.Ширина должна быть небольшой, т.е.символ (15) или что-то разумное.И это лучше всего работает в онлайновых системах, потому что вы обычно извлекаете только небольшое количество строк, поэтому необходимость "обрезать" те конечные пробелы, которые вы получите в результирующем наборе, является тривиальной задачей, в отличие от необходимости присоединять миллионы строк из одной таблицы к миллионам строк в другой таблице.

Еще одна причина, по которой CHAR имеет смысл по сравнению с varchar в онлайн-системах, заключается в том, что это уменьшает разбиение страниц.Используя char , вы, по сути, "резервируете" (и тратите впустую) это пространство, поэтому, если пользователь придет позже и поместит больше данных в этот столбец, SQL уже выделил для него место, и оно уходит.

Другая причина использования CHAR аналогична второй причине.Если программист или пользователь выполняет "пакетное" обновление миллионов строк, добавляя, например, какое-нибудь предложение в поле примечания, вам не позвонит администратор базы данных посреди ночи, интересуясь, почему их диски заполнены.Другими словами, это приводит к более предсказуемому росту размера базы данных.

Итак, это 3 способа, которыми онлайн-система (OLTP) может извлечь выгоду из char по сравнению с varchar.Я почти никогда не использую char в сценарии хранилища / анализа / OLAP, потому что обычно у вас ТАК много данных, что все эти столбцы char могут привести к большому количеству потраченного впустую пространства.

Имейте в виду, что char может значительно увеличить вашу базу данных, но большинство инструментов резервного копирования поддерживают сжатие данных, поэтому ваши резервные копии, как правило, будут примерно того же размера, как если бы вы использовали varchar.Например, LiteSpeed или RedGate SQL Backup.

Другое применение - в представлениях, созданных для экспорта данных в файл фиксированной ширины.Допустим, мне нужно экспортировать некоторые данные в плоский файл для чтения мэйнфреймом.Это фиксированная ширина (без разделителей).Мне нравится хранить данные в моей "промежуточной" таблице как varchar (таким образом, занимая меньше места в моей базе данных), а затем использовать представление, чтобы ПРИВЕСТИ все к его эквиваленту char, с длиной, соответствующей ширине фиксированной ширины для этого столбца.Например:

create table tblStagingTable (
pkID BIGINT (IDENTITY,1,1),
CustomerFirstName varchar(30),
CustomerLastName varchar(30),
CustomerCityStateZip varchar(100),
CustomerCurrentBalance money )

insert into tblStagingTable
(CustomerFirstName,CustomerLastName, CustomerCityStateZip) ('Joe','Blow','123 Main St Washington, MD 12345', 123.45)

create view vwStagingTable AS
SELECT CustomerFirstName = CAST(CustomerFirstName as CHAR(30)),
CustomerLastName = CAST(CustomerLastName as CHAR(30)),
CustomerCityStateZip = CAST(CustomerCityStateZip as CHAR(100)),
CustomerCurrentBalance = CAST(CAST(CustomerCurrentBalance as NUMERIC(9,2)) AS CHAR(10))

SELECT * from vwStagingTable

Это круто, потому что внутренне мои данные занимают меньше места, потому что они используют varchar.Но когда я использую DTS или SSIS или даже просто вырезаю и вставляю из SSMS в Блокнот, я могу использовать представление и получить нужное количество конечных пробелов.В DTS у нас раньше была функция под названием, черт, я забыл, кажется, она называлась "предложить столбцы" или что-то в этом роде.В SSIS вы больше не можете этого делать, вам нужно утомительно определить диспетчер подключений к плоским файлам.Но поскольку у вас настроено представление, служба службы безопасности может знать ширину каждого столбца, и это может сэкономить много времени при построении ваших задач потока данных.

Итак, итог...используйте varchar .Существует очень небольшое количество причин для использования char, и это только из соображений производительности.Если у вас система с сотнями миллионов строк, вы увидите заметную разницу, если предикаты являются детерминированными (char), но для большинства систем использование char - это просто пустая трата места.

Надеюсь, это поможет.Джефф

Есть преимущества в производительности, но вот одно из них, которое не было упомянуто:миграция строк.С помощью символа char вы заранее резервируете все пространство.Итак, допустим, у вас есть символ char (1000), и вы сохраняете 10 символов, вы израсходуете все 1000 символов пространства.В переменной char2(1000) вы будете использовать только 10 символов.Проблема возникает, когда вы изменяете данные.Допустим, вы обновили столбец, чтобы он теперь содержал 900 символов.Возможно, что пространство для расширения varchar недоступно в текущем блоке.В этом случае механизм базы данных должен перенести строку в другой блок и создать указатель в исходном блоке на новую строку в новом блоке.Чтобы прочитать эти данные, движку базы данных теперь придется прочитать 2 блока.
Никто не может однозначно сказать, что varchar или char лучше.Существует пространство для временного компромисса и рассмотрения вопроса о том, будут ли данные обновляться, особенно если есть большая вероятность, что они будут расти.

Существует разница между ранней оптимизацией производительности и использованием правил наилучшего практического типа.Если вы создаете новые таблицы, где у вас всегда будет поле фиксированной длины, имеет смысл использовать CHAR , вы должны использовать его в этом случае.Это не ранняя оптимизация, а скорее реализация эмпирического правила (или наилучшей практики).

т. е.- Если у вас есть поле состояния из 2 букв, используйте CHAR(2) .Если у вас есть поле с фактическими названиями состояний, используйте VARCHAR .

Я бы выбрал varchar, если только в столбце не хранится фиксированное значение, такое как код штата США, длина которого всегда составляет 2 символа, а список допустимых кодов штатов США меняется не часто :).

В любом другом случае, даже при сохранении хэшированного пароля (который имеет фиксированную длину), я бы выбрал varchar.

Почему столбец типа -- char всегда заполняется пробелами, что делает для столбца моя колонка определяется как char(5) со значением 'ABC' внутри сравнения:

my_column = 'ABC' -- my_column stores 'ABC  ' value which is different then 'ABC'

ложь.

Это особенность это может привести ко множеству раздражающих ошибок во время разработки и усложнит тестирование.

CHAR занимает меньше места в памяти, чем VARCHAR, если все ваши значения данных в этом поле имеют одинаковую длину.Теперь, возможно, в 2009 году база данных объемом 800 ГБ по сути такая же, как и 810 ГБ, если вы преобразовали переменные в символы, но для коротких строк (1 или 2 символа), я бы сказал, CHAR по-прежнему является отраслевой "лучшей практикой".

Теперь, если вы посмотрите на большое разнообразие типов данных, предоставляемых большинством баз данных, даже для одних только целых чисел (bit, tiny, int, bigint), есть причины предпочесть одно другому.Просто выбирая bigint каждый раз, на самом деле вы немного не осведомлены о целях и использовании поля.Если поле просто представляет возраст человека в годах, то bigint - это перебор.Теперь это не обязательно "неправильно", но и неэффективно.

Но это интересный аргумент, и по мере того, как базы данных со временем совершенствуются, можно утверждать, что сравнение CHAR с VARCHAR становится менее актуальным.

Я поддерживаю комментарий Джима Маккита.

Кроме того, индексация и полное сканирование таблицы выполняются быстрее, если в вашей таблице есть только столбцы CHAR.По сути, оптимизатор сможет предсказать, насколько велика каждая запись, если в ней есть только столбцы CHAR, в то время как ему необходимо проверить значение размера каждого столбца VARCHAR.

Кроме того, если вы обновите столбец VARCHAR до размера, превышающего его предыдущее содержимое, вы можете заставить базу данных перестроить свои индексы (потому что вы заставили базу данных физически переместить запись на диск).В то время как со столбцами CHAR этого никогда не произойдет.

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

Вспомните мудрые слова Джикстры.Ранняя оптимизация производительности - это корень всех зол.

Многие люди отмечали, что если вы знаете точную длину значения, использование CHAR имеет некоторые преимущества.Но хотя сегодня сохранение штатов США в виде символа (2) - это здорово, когда вы получаете сообщение от отдела продаж о том, что "Мы только что совершили нашу первую продажу в Австралию", вы испытываете боль.Я всегда отправляю, чтобы переоценить, какой длины, по моему мнению, должны быть поля, вместо того, чтобы делать "точные" предположения для покрытия будущих событий.VARCHAR даст мне больше гибкости в этой области.

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

Это классический компромисс между пространством и производительностью.

В MS SQL 2005 Varchar (или NVarchar для языков, требующих двух байт на символ, т.е. китайский) имеет переменную длину.Если вы добавите данные в строку после того, как они были записаны на жесткий диск, это приведет к размещению данных в месте, не смежном с исходной строкой, и приведет к фрагментации ваших файлов данных.Это повлияет на производительность.

Итак, если пространство не является проблемой, то Char лучше подходит для повышения производительности, но если вы хотите уменьшить размер базы данных, то varchars лучше.

Я думаю, что в вашем случае, вероятно, нет причин не выбирать Varchar.Это дает вам гибкость, и, как уже упоминалось рядом респондентов, производительность сейчас такова, что, за исключением очень специфических обстоятельств, простые смертные (в отличие от администраторов баз данных Google) не заметят разницы.

Интересная вещь, которую стоит отметить, когда речь заходит о типах БД, - это sqlite (популярная мини-база данных с довольно впечатляющей производительностью), которая помещает все в базу данных в виде строки и вводит типы на лету.

Я всегда использую VarChar и обычно делаю его намного больше, чем мне может понадобиться.Например.50 для имени, как вы говорите, почему бы и нет, просто на всякий случай.

Фрагментация.Char резервирует пространство, а VarChar - нет.Разделение страницы может потребоваться для размещения обновления в varchar.

Я бы НИКОГДА не стал использовать символы chars.Я обсуждал этот вопрос со многими людьми, и они всегда упоминают избитое клише о том, что char работает быстрее.Ну, я спрашиваю, насколько быстрее?О чем мы здесь говорим, миллисекундах, секундах, и если да, то сколько?Вы хотите сказать мне, что из-за того, что кто-то утверждает, что это на несколько миллисекунд быстрее, мы должны внедрить в систему тонны трудно исправляемых ошибок?

Итак, вот некоторые проблемы, с которыми вы столкнетесь:

Каждое поле будет дополнено, так что в итоге вы навсегда получите код, в котором везде есть RTRIMS.Это также огромная трата дискового пространства для более длинных полей.

Теперь предположим, что у вас есть типичный пример поля char, состоящего всего из одного символа, но это поле является необязательным.Если кто-то передает пустую строку в это поле, она становится одним пробелом.Поэтому, когда другое приложение / процесс запрашивает его, они получают один пробел, если они не используют rtrim.У нас были XML-документы, файлы и другие программы, которые отображали только один пробел в необязательных полях и прерывали работу.

Итак, теперь вы должны убедиться, что передаете в поле char значения null, а не пустую строку.Но это неправильное использование null .Вот как используется значение null.Допустим, вы получаете файл от поставщика

Имя|Пол|Город

Боб||Лос-Анджелес

Если пол не указан, то вы вводите в таблицу Bob, пустую строку и Los Angeles.Теперь предположим, что вы получаете файл, и его формат меняется, и пол больше не включается, но был в прошлом.

Название|Город

Боб|Сиэтл

Ну а теперь, поскольку гендер не включен, я бы использовал null .Переменные поддерживают это без проблем.

С другой стороны, Char - это другое дело.Вы всегда должны отправлять null.Если вы когда-нибудь отправите пустую строку, в итоге вы получите поле, в котором есть пробелы.

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

при использовании значений varchar SQL Server требуется дополнительно 2 байта на строку для хранения некоторой информации об этом столбце, тогда как при использовании char это не требуется поэтому, если вы

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

Из-за этого у вас нет никакой экономии места при использовании VARCHAR(200) по сравнению с CHAR(200)

Использование CHAR (NCHAR) и VARCHAR (NVARCHAR) приводит к различиям в способах хранения данных сервером базы данных.Первый вводит завершающие пробелы;Я столкнулся с проблемой при использовании его с оператором LIKE в функциях SQL SERVER.Поэтому я должен сделать это безопасным, постоянно используя VARCHAR (NVARCHAR).

Например, если у нас есть таблица ТЕСТ (ID INT, Status CHAR(1)), и вы пишете функцию для перечисления всех записей с некоторым конкретным значением , например следующим:

CREATE FUNCTION List(@Status AS CHAR(1) = '')
RETURNS TABLE
AS
RETURN
SELECT * FROM TEST
WHERE Status LIKE '%' + @Status '%'

В этой функции мы ожидаем, что когда мы введем параметр по умолчанию, функция вернет все строки, но на самом деле это не так.Изменение типа данных @Status на VARCHAR устранит проблему.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top