Я понимаю, что CHAR рекомендуется, если все мои значения фиксированной ширины. Но что с того? Почему бы просто не выбрать VARCHAR для всех текстовых полей, просто чтобы быть в безопасности.
Я понимаю, что CHAR рекомендуется, если все мои значения фиксированной ширины. Но что с того? Почему бы просто не выбрать VARCHAR для всех текстовых полей, просто чтобы быть в безопасности.
Ответы:
Обычно выбирайте CHAR, если все строки будут иметь одинаковую длину . Выберите VARCHAR, когда длина значительно меняется . CHAR также может быть немного быстрее, потому что все строки имеют одинаковую длину.
Это зависит от реализации БД, но обычно VARCHAR использует еще один или два байта памяти (для длины или завершения) в дополнение к фактическим данным. Таким образом (при условии, что вы используете однобайтовый набор символов), сохраняя слово "FooBar"
Суть в том, что CHAR может быть быстрее и более эффективно использовать пространство для данных относительно одинаковой длины (с разницей длины в два символа).
Примечание : Microsoft SQL имеет 2 байта служебной информации для VARCHAR. Это может варьироваться от DB к DB, но обычно для указания длины или EOL на VARCHAR требуется как минимум 1 байт служебной информации.
Как было отмечено Gaven в комментариях, если вы используете многобайтовый набор символов переменной длины, такой как UTF8, то CHAR хранит максимальное количество байтов, необходимое для хранения количества символов. Таким образом, если UTF8 требуется максимум 3 байта для хранения символа, то для CHAR (6) будет установлено значение 18 байтов, даже если будет храниться только латинский 1 символ. Таким образом, в этом случае VARCHAR становится намного лучшим выбором.
Если вы работаете со мной, и вы работаете с Oracle, я, вероятно, заставил бы вас использовать его varchar
практически в любых обстоятельствах. Предположение, что char
используется меньше вычислительной мощности, чем varchar
может быть верно ... пока ... но движки баз данных со временем становятся лучше, и такого рода общее правило создает будущий "миф".
Другое дело: я никогда не видел проблемы с производительностью, потому что кто-то решил пойти с varchar
. Вы будете гораздо лучше использовать свое время для написания хорошего кода (меньше обращений к базе данных) и эффективного SQL (как работают индексы, как оптимизатор принимает решения, почему exists
быстрее, чем in
обычно ...).
Заключительная мысль: я видел все виды проблем с использованием CHAR
, людей, ищущих «когда они должны искать», или людей, ищущих «FOO», когда они должны искать «FOO (куча пробелов здесь)» или люди, не обрезающие конечные пробелы, или ошибки с Powerbuilder, добавляющие до 2000 пробелов к значению, которое он возвращает из процедуры Oracle.
В дополнение к преимуществам производительности, CHAR
может использоваться, чтобы указать, что все значения должны быть одинаковой длины, например, столбец для сокращений штатов США.
CHAR
, вы должны убедиться, что ваши ограничения скидки отступают.
Char немного быстрее, поэтому, если у вас есть столбец, который, как вы ЗНАЕТЕ, будет определенной длины, используйте char. Например, хранение (M) ale / (F) emale / (U), неизвестное для пола, или 2 символа для штата США.
NChar или Char работают лучше, чем их альтернативные варианты?
Отличный вопрос Простой ответ - да в определенных ситуациях. Посмотрим, можно ли это объяснить.
Очевидно, мы все знаем, что если я создам таблицу со столбцом varchar (255) (назовем этот столбец myColumn) и вставим миллион строк, но поместим в myColumn только несколько символов для каждой строки, таблица будет намного меньше (в целом количество страниц данных, необходимых для механизма хранения), чем если бы я создал myColumn как char (255). Каждый раз, когда я выполняю операцию (DML) с этой таблицей и запрашиваю много строк, будет быстрее, когда myColumn varchar, потому что мне не нужно перемещаться вокруг всех этих «лишних» пробелов в конце. Перемещение, например, когда SQL Server выполняет внутреннюю сортировку, например, во время отдельной операции или операции объединения, или если он выбирает объединение во время плана запроса и т. Д.
Но есть некоторые накладные расходы при использовании 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 (таким образом, занимая меньше места в моей базе данных), а затем использовать представление для CAST всего, что эквивалентно символу, с длиной, соответствующей ширине фиксированной ширины для этого столбца. , Например:
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 вы больше не можете этого делать, вам нужно утомительно определять менеджер соединений с плоскими файлами. Но так как у вас есть настройки вида, SSIS может знать ширину каждого столбца и может сэкономить много времени при построении ваших задач потока данных.
Итак, суть ... используйте varchar. Существует очень мало причин использовать char, и это только из-за производительности. Если у вас есть система с сотнями миллионов строк, вы увидите заметную разницу, если предикаты являются детерминированными (char), но для большинства систем использование char просто тратит пространство.
Надеюсь, это поможет. Джефф
Есть преимущества в производительности, но здесь не упоминалось: миграция строк. С помощью char вы резервируете все пространство заранее. Итак, скажем, у вас есть char (1000), и вы храните 10 символов, вы будете использовать все 1000 символов charaters. В varchar2 (1000) вы будете использовать только 10 символов. Проблема возникает, когда вы изменяете данные. Допустим, вы обновили столбец, чтобы теперь он содержал 900 символов. Возможно, что пространство для расширения varchar не доступно в текущем блоке. В этом случае механизм БД должен перенести строку в другой блок и сделать указатель в исходном блоке на новую строку в новом блоке. Чтобы прочитать эти данные, движку БД теперь придется прочитать 2 блока.
Никто не может однозначно сказать, что varchar или char лучше. Существует пространство для временного компромисса и рассмотрения вопроса о том, будут ли данные обновляться, особенно если есть хорошие шансы на их рост.
Существует разница между ранней оптимизацией производительности и использованием правил, основанных на рекомендациях. Если вы создаете новые таблицы, в которых у вас всегда будет поле фиксированной длины, имеет смысл использовать CHAR, вам следует использовать его в этом случае. Это не ранняя оптимизация, а скорее внедрение практического правила (или лучшей практики).
т.е. - если у вас есть поле состояния из 2 букв, используйте CHAR (2). Если у вас есть поле с фактическими именами состояний, используйте VARCHAR.
Я бы выбрал varchar, если в столбце не хранится фиксированное значение, например, код штата США - который всегда имеет длину 2 символа, а список допустимых кодов штатов США меняется не часто :).
В любом другом случае, даже при хранении хешированного пароля (фиксированной длины), я бы выбрал varchar.
Почему - столбец типа char всегда выполняется с пробелами, что делает столбец my_column определенным как char (5) со значением 'ABC' внутри сравнения:
my_column = 'ABC' -- my_column stores 'ABC ' value which is different then 'ABC'
ложный.
Эта функция может привести к множеству раздражающих ошибок во время разработки и усложняет тестирование.
CHAR занимает меньше места, чем VARCHAR, если все ваши значения данных в этом поле имеют одинаковую длину. Теперь, возможно, в 2009 году база данных объемом 800 ГБ для всех намерений и целей будет такой же, как и 810 ГБ, если вы конвертируете VARCHAR в CHAR, но для коротких строк (1 или 2 символа) CHAR по-прежнему остается «лучшей практикой» в отрасли, я бы сказал.
Теперь, если вы посмотрите на большое разнообразие типов данных, которые большинство баз данных предоставляют даже для одних целых чисел (bit, tiny, int, bigint), есть причины выбрать один из других. Простой выбор bigint каждый раз на самом деле немного неосведомлен о целях и использовании этой области. Если поле просто представляет возраст людей в годах, bigint является излишним. Теперь это не обязательно «неправильно», но это не эффективно.
Но это интересный аргумент, и, поскольку базы данных со временем улучшаются, можно утверждать, что CHAR против VARCHAR становится менее актуальным.
Я поддерживаю комментарий Джима Маккита.
Кроме того, индексирование и полное сканирование таблицы выполняются быстрее, если в вашей таблице только столбцы CHAR. По сути, оптимизатор сможет предсказать, насколько велика каждая запись, если в ней есть только столбцы CHAR, тогда как ему необходимо проверить значение размера каждого столбца VARCHAR.
Кроме того, если вы обновите столбец VARCHAR до размера, превышающего его предыдущее содержимое, вы можете заставить базу данных перестроить свои индексы (потому что вы заставили базу данных физически переместить запись на диск). Хотя со столбцами CHAR этого никогда не произойдет.
Но вы, вероятно, не будете заботиться о снижении производительности, если у вас огромный стол.
Помните мудрые слова Джикстры. Ранняя оптимизация производительности - корень всего зла.
CHAR
столбец, индексы также должны обновляться. В этом отношении нет разницы в обновлении столбца VARCHAR или CHAR. Подумайте об обновлении FOO
до BAR
.
Многие люди отмечают, что если вы знаете точную длину значения, использование CHAR имеет некоторые преимущества. Но несмотря на то, что сохранение американских штатов в виде CHAR (2) сегодня прекрасно, когда вы получаете сообщение от продаж, что «Мы только что сделали нашу первую продажу в Австралию», вы находитесь в мире боли. Я всегда посылаю, чтобы переоценить, как долго, я думаю, поля должны быть, а не делать «точное» предположение, чтобы покрыть будущие события. VARCHAR даст мне больше гибкости в этой области.
Я думаю, что в вашем случае, вероятно, нет причин не выбирать Varchar. Это дает вам гибкость, и, как уже упоминалось рядом респондентов, производительность теперь такова, что за исключением очень специфических обстоятельств мы, простые смертные (в отличие от администраторов Google), не заметим разницы.
Интересная вещь, которую стоит отметить, когда дело доходит до DB Types, это то, что sqlite (популярная мини-база данных с довольно впечатляющей производительностью) помещает все в базу данных в виде строки и печатает на лету.
Я всегда использую VarChar и обычно делаю его намного больше, чем мне может понадобиться. Например. 50 для Имя, как вы говорите, почему бы просто не быть в безопасности.
Я бы никогда не использовал символы. У меня были эти дебаты со многими людьми, и они всегда поднимают усталое клише, что символ быстрее. Ну, я говорю, насколько быстрее? О чем мы здесь говорим, миллисекундах, секундах и если да, то сколько? Вы говорите мне, потому что кто-то утверждает, что это на несколько миллисекунд быстрее, мы должны ввести в систему тонны трудно исправляемых ошибок?
Итак, вот некоторые проблемы, с которыми вы столкнетесь:
Каждое поле будет дополнено, так что вы всегда будете иметь код, который везде имеет RTRIMS. Это также огромная трата дискового пространства для более длинных полей.
Теперь предположим, что у вас есть типичный пример поля char, состоящего всего из одного символа, но поле является необязательным. Если кто-то передает пустую строку в это поле, он становится одним пробелом. Поэтому, когда другое приложение / процесс запрашивает его, они получают один пробел, если они не используют rtrim. У нас были XML-документы, файлы и другие программы, отображающие только один пробел в необязательных полях и разбивающие вещи.
Итак, теперь вы должны убедиться, что вы передаете пустые строки, а не пустые, в поле char. Но это НЕ правильное использование нуля. Вот использование нуля. Допустим, вы получили файл от поставщика
Имя | Пол | Город
Боб || Лос-Анджелес
Если пол не указан, введите в таблицу Боба, пустую строку и Лос-Анджелес. Теперь предположим, что вы получили файл и его формат изменился, и пол больше не включен, но был в прошлом.
Имя | Город
Боб | Сиэтл
Ну, теперь, поскольку пол не включен, я бы использовал нуль. Varchars поддерживают это без проблем.
Чар с другой стороны отличается. Вы всегда должны отправить ноль. Если вы когда-нибудь отправите пустую строку, вы получите поле с пробелами.
Я мог бы продолжать и исправлять все ошибки, которые мне пришлось исправить с помощью символов и примерно через 20 лет разработки.
При вычислении фактического необходимого размера для значения столбца и выделении пространства для Varchar есть небольшие накладные расходы, поэтому, если вы точно уверены, как долго значение будет всегда, лучше использовать Char и избегать попадания.
Это классический компромисс между производительностью и производительностью.
В MS SQL 2005 Varchar (или NVarchar для языков, требующих два байта на символ, т.е. китайский), имеют переменную длину. Если вы добавите в строку после того, как она была записана на жесткий диск, она поместит данные в неконкурентном месте в исходную строку и приведет к фрагментации ваших файлов данных. Это повлияет на производительность.
Итак, если пространство не является проблемой, то Char лучше для производительности, но если вы хотите уменьшить размер базы данных, тогда varchars лучше.
Фрагментация. Char резервирует пространство, а VarChar - нет. Разделение страницы может потребоваться для размещения обновления до varchar.
CHAR
столбца может произойти разделение страницы .
В некоторых базах данных SQL VARCHAR будет дополнен до максимального размера, чтобы оптимизировать смещения, чтобы ускорить полное сканирование таблиц и индексов.
Из-за этого у вас нет экономии места при использовании VARCHAR (200) по сравнению с CHAR (200)
Использование CHAR (NCHAR) и VARCHAR (NVARCHAR) приводит к различиям в способах хранения данных сервером базы данных. Первый вводит конечные пробелы; Я столкнулся с проблемой при использовании его с оператором LIKE в функциях SQL SERVER. Поэтому я должен сделать это безопасно, используя VARCHAR (NVARCHAR) все время.
Например, если у нас есть таблица TEST (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, чтобы устранить проблему.