Каковы варианты использования для выбора CHAR над VARCHAR в SQL? - PullRequest
267 голосов
/ 12 сентября 2008

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

Ответы [ 19 ]

381 голосов
/ 12 сентября 2008

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

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

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

Нижняя строка: CHAR может быть быстрее и более с эффективным использованием пространства для данных относительно одинаковой длины (с разницей в длину двух символов).

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

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

64 голосов
/ 12 сентября 2008

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

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

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

30 голосов
/ 12 сентября 2008

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

18 голосов
/ 12 сентября 2008

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

16 голосов
/ 04 марта 2011

Работает ли 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. </p>

Таким образом, если 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 просто тратит пространство.

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

9 голосов
/ 13 сентября 2008

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

8 голосов
/ 12 сентября 2008

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

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

8 голосов
/ 13 сентября 2008

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

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

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

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

ложь.

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

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

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

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

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

4 голосов
/ 12 сентября 2008

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...