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


Char немного быстрее, поэтому, если у вас есть столбец, который, как вы ЗНАЕТЕ, будет определенной длины, используйте char. Например, запоминание (M) ale / (F) emale / (U) неизвестно для пола или 2 символов для штата США.
Мне кажется, что набор состояний не обязательно неизменяем, поэтому char (2) кажется гораздо более подходящим, чем перечисление.
@Bobby Jack - я не знаю конкретных деталей какой-либо конкретной реализации перечисления SQL, но имейте в виду, что перечисление, сохраненное как 4-байтовое целое число, может потребовать больше места, чем столбец char (1) или char (2) с те же данные. В некотором смысле перечисления более логичны с точки зрения их интерпретации, и это может быть убедительным, но все в системе РСУБД на определенном уровне абстрактно и зависит от предикатов, определенных для таблиц.
Плохой пример, ENUM лучше всего для этого случая. Лучшим примером может быть трехбуквенный код аэропорта IATA.
@Andrew, не все db поддерживают типы данных ENUM. MSSQLServer, например, этого не делает. Кроме того, ENUM, хранящийся как int, занимает 4 байта. CHAR (1) занимает 1 байт, а NCHAR (1) занимает 2 байта.
@Jarrett - я думаю, что ENUM обычно хранится как TINYINT
Есть небольшие накладные расходы на обработку при вычислении фактического необходимого размера для значения столбца и выделении пространства для Varchar, поэтому, если вы точно уверены, какой длины всегда будет значение, лучше использовать Char и избегать попадания.
при использовании значений varchar SQL Server требует дополнительных 2 байта на строку для хранения некоторой информации об этом столбце, тогда как если вы используете char, это не нужно так что если вы
Общее правило - выбрать СИМВОЛ, если все строки будут близки к такая же длина. Выберите VARCHAR (или NVARCHAR), когда длина варьируется значительно. CHAR также может быть немного быстрее, потому что все строки имеют одинаковую длину.
Это зависит от реализации БД, но обычно VARCHAR (или NVARCHAR) использует еще один или два байта памяти (для длины или завершения) в дополнение к фактическим данным. Итак (при условии, что вы используете однобайтовый набор символов), сохраняя слово «FooBar»
Нижняя строка: СИМВОЛ, может, Быстрее и более компактный для данных относительно одинаковой длины (в пределах двух символов разницы в длине).
Примечание: Microsoft SQL имеет 2 байта служебных данных для VARCHAR. Это может варьироваться от БД к БД, но обычно требуется как минимум 1 байт служебных данных для указания длины или EOL в VARCHAR.
Как было указано Гавен в комментариях: все меняется, когда дело доходит до наборов многобайтовые символы, и это тот случай, когда VARCHAR становится гораздо лучшим выбором.
Примечание о заявленной длине VARCHAR: поскольку он хранит длину фактического содержимого, вы не теряете неиспользованную длину. Таким образом, для хранения 6 символов в VARCHAR (6), VARCHAR (100), или же VARCHAR (МАКС) используется такой же объем памяти. Узнайте больше о различиях при использовании VARCHAR (МАКС.). Вы объявляете размер максимум в VARCHAR, чтобы ограничить объем хранимого.
В комментариях AlwaysLearning указал, что Документы Microsoft Transact-SQL, похоже, говорит об обратном. Я бы предположил, что это ошибка или, по крайней мере, документы неясны.
Другая причина - разбиение и фрагментация страниц. У меня была таблица с IDEN PK, которая на 99% фрагментирована из-за разбиения страниц на столбцы varchar. Очень активная таблица и по характеру приложения новая пустая строка будет создана и затем заполнена. Чар исправил проблему фрагментации.
@Jim McKeeth - эти расчеты верны, только если вы используете кодировку latin1. Поскольку в наши дни большинство людей должны использовать utf8, ваши столбцы CHAR будут использовать в среднем в 3 раза больше места в качестве VARCHAR, который хранит в основном символы в базовой многоязычной плоскости.
@GavinTowey Я сказал, что он предполагает однобайтовый набор символов. Вы хотите сказать, что UTF8 занимает в CHAR в 3 раза больше места, чем в VARCAR? Итак, 3 буквы в CHAR - это 9 байтов, а в VARCAR - 3?
@JimMcKeeth да, это совершенно верно. Поскольку CHAR имеет фиксированную длину, он должен быть зафиксирован на максимально возможном пространстве, которое может быть использовано. В UTF8 это 3 байта на символ. Для varchar можно использовать 1-3 байта на символ по мере необходимости. Это в руководстве MySQL: dev.mysql.com/doc/refman/5.0/en/charset-unicode-utf8.html
В чем разница между строками FooBar и varchar (100) vs char (100)? Я думаю, это лучше демонстрирует разницу, да? Нет?
@Nenotlep Для строки "FooBar" VARCHAR (100) будет 8 байтов (2 байта служебных данных), а CHAR (100) будет 100 байтов (служебные данные 94 байта). Когда вы используете CHAR, вы выделяете фиксированное количество байтов, указанное во время разработки. Когда вы используете VARCHAR, распределение пространства изменяется при изменении данных и всегда имеет 2 байта служебных данных (предположительно для хранения текущей длины данных переменной длины).
@GavinTowey SQLSERVER использует UCS-2 для своих типов данных NCHAR и NVARCHAR. Всегда два байта на символ.
@JimMcKeeth - важно отметить, что для MS SQL Server, столбца с многобайтовым включением, НЕ БУДЕТ брать больше байтов для выделения строки, вместо этого он ограничивает количество символов. Из документации: «Для наборов символов многобайтовой кодировки размер хранилища по-прежнему равен n байтам, но количество символов, которые могут быть сохранены, может быть меньше n». docs.microsoft.com/en-us/sql/t-sql/data-types/…
также на той же странице документации: «Распространенное заблуждение - думать, что CHAR (n) и VARCHAR (n), n определяет количество символов. Но в CHAR (n) и VARCHAR (n) n определяет длину строки в байтах (0-8000). n никогда не определяет количество символов, которые могут быть сохранены. Это похоже на определение NCHAR (n) и NVARCHAR (n) ».
@GavinTowey ваше утверждение неверно для MS SQL Server. Пожалуйста, смотрите мои замечания выше.
@JimMcKeeth Должен ли пример VARCHAR содержать не 4 байта служебных данных? 2 байта для длины и 2 неиспользуемых байта для символов.
@alwaysLearning В этом суть VARCHAR. Если бы вы сказали VARCHAR (2000), у него все равно было бы 2 байта служебных данных. Вы сохраняете длину, поэтому вам не понадобится неиспользуемое пространство.
@JimMcKeeth Раньше я так думал. Однако, наткнувшись на этот QA, я прочитал этот документ Microsoft (docs.microsoft.com/en-us/sql/t-sql/data-types/…), и в нем они указывают, что используется хранилище n + 2. Вы можете найти это в разделе «Аргументы». Возможно, я неправильно истолковываю документ.
@alwaysLearning Я бы предположил, что это ошибка документации или, по крайней мере, непонятная. В противном случае, зачем использовать оба, поскольку VARCHAR всегда будет занимать больше памяти, чем одно и то же объявление CHAR.
Я поддерживаю комментарий Джима МакКита.
Кроме того, индексация и полное сканирование таблицы выполняются быстрее, если в таблице есть только столбцы типа CHAR. По сути, оптимизатор сможет предсказать размер каждой записи, если в ней есть только столбцы CHAR, при этом ему необходимо проверить значение размера каждого столбца VARCHAR.
Кроме того, если вы обновляете столбец VARCHAR до размера, превышающего его предыдущее содержимое, вы можете заставить базу данных перестроить свои индексы (потому что вы заставили базу данных физически переместить запись на диск). В то время как со столбцами CHAR этого никогда не произойдет.
Но вы, вероятно, не будете заботиться о снижении производительности, если ваша таблица не будет огромной.
Помните мудрые слова Джикстры. Ранняя оптимизация производительности - корень всех зол.
В вашем комментарии есть некоторые предположения. Я снова и снова видел, как подобные предположения проверялись, и прямо противоположное оказывалось верным. Проблема в том, что многие инженеры примут такую информацию как евангелие. Пожалуйста, ребята, создайте тестовые примеры, которые отражают ваши реальные ситуации.
Итан совершенно прав. Это настолько зависит от реализации, которую вы используете, что без ссылок на фактический (продукт, версию) это совершенно бесполезно.
Когда вы обновляете столбец CHAR, индексы также должны быть обновлены. В этом отношении нет никакой разницы в обновлении столбца VARCHAR или CHAR. Подумайте об обновлении FOO до BAR.
В некоторых базах данных SQL VARCHAR будет дополнен до максимального размера, чтобы оптимизировать смещения. Это необходимо для ускорения полного сканирования таблиц и индексов.
Из-за этого у вас нет экономии места при использовании VARCHAR (200) по сравнению с CHAR (200)
Какие базы данных реализуют VARCHAR таким образом?
Серьезно, какая база данных реализует это таким образом? То, что вы описываете, обычно относится к CHAR, а не к VARCHAR.
mysql преобразует varchar в символы, если в одной таблице есть char и varchar.
Моя интерпретация комментариев MySQL заключается в том, что это не относится к хранилищу первичных таблиц, но, возможно, может иметь отношение к временным таблицам, например. для группировки / сортировки данных. dev.mysql.com/doc/refman/8.0/en/char.htmlstackoverflow.com/questions/262238/…
Существует разница между оптимизацией производительности на раннем этапе и использованием правил передового опыта. Если вы создаете новые таблицы, в которых всегда будет поле фиксированной длины, имеет смысл использовать CHAR, вы должны использовать его в этом случае. Это не ранняя оптимизация, а реализация практического правила (или передовой практики).
т.е. - Если у вас есть двухбуквенное поле состояния, используйте CHAR (2). Если у вас есть поле с фактическими именами состояний, используйте VARCHAR.
Если вы работаете со мной и работаете с Oracle, я, вероятно, заставлю вас использовать varchar почти в любых обстоятельствах. Предположение о том, что char использует меньшую вычислительную мощность, чем varchar, может быть верным ... на данный момент ... но механизмы баз данных со временем становятся лучше, и такое общее правило создало будущий "миф".
Еще одна вещь: я никогда не видел проблем с производительностью, потому что кто-то решил пойти с varchar. Вы гораздо лучше потратите свое время на написание хорошего кода (меньше обращений к базе данных) и эффективного SQL (как работают индексы, как оптимизатор принимает решения, почему exists обычно быстрее, чем in ...).
Заключительная мысль: я видел всевозможные проблемы с использованием CHAR, людей, которые ищут «когда они должны искать», или людей, которые ищут «FOO», когда им следует искать «FOO» (здесь куча пробелов) ', или люди, не обрезающие конечные пробелы, или ошибки с Powerbuilder, добавляющие до 2000 пробелов к значению, которое он возвращает из процедуры Oracle.
Я несколько не согласен с вашим первым абзацем, поскольку char может дать подсказку, которая может быть полезна оптимизаторам, даже будущим, и может помочь сообщить о назначении столбца. Но +1 за ваш третий абзац. Ненавижу лишние места. Поле должно просто хранить все, что я помещаю в него, без всяких [поясняющих] отступов. По сути, я просто использую char, если все данные должны быть одинаковой длины, не больше и не меньше, сейчас и навсегда. Это, конечно, очень редко, и обычно это char (1).
char также дает подсказки аналитикам и разработчикам ... это x количество символов ... Если они думают о сериализации в каком-то другом формате, это может быть полезно. (Я был вынужден сохранить контрольную сумму md5 в char в mssql, у которого не было типа uuid ... и я никогда не хотел ничего <32 байта ... также наложил ограничение на столбец).
Помимо повышения производительности, CHAR может использоваться для обозначения того, что все значения должен имеют одинаковую длину, например, столбец для сокращений штатов США.
Или коды стран - могут помочь различить использование сокращения кода страны из 2 или 3 символов.
Если это действительно фиксированная длина, тогда должно быть ограничение, обеспечивающее это. Хотя, если вы используете CHAR, вам нужно убедиться, что ваше ограничение не допускает заполнения.
Я бы выбрал varchar, если столбец не хранит фиксированное значение, такое как код штата США, который всегда составляет 2 символа, а список действительного кода штатов США не часто меняется :).
В любом другом случае, даже при хранении хешированного пароля (фиксированной длины), я бы выбрал varchar.
Почему - столбец типа char всегда заполняется пробелами, поэтому столбец my_column определяется как char (5) со значением 'ABC' внутри сравнения:
my_column = 'ABC' -- my_column stores 'ABC ' value which is different then 'ABC'
ложный.
Этот особенность может привести к множеству раздражающих ошибок во время разработки и усложнить тестирование.
По крайней мере, на сервере MSSQL «abc» = «abc». Я так и не понял, нравится мне эта функция или нет ...
Хорошее прочтение о заполнении char здесь Прокладка
Есть преимущества в производительности, но вот одно из них, о котором не упоминалось: миграция строк. С помощью char вы заранее резервируете все пространство. Допустим, у вас есть char (1000) и вы храните 10 символов, вы используете все 1000 символов пространства. В varchar2 (1000) вы будете использовать только 10 символов. Проблема возникает, когда вы изменяете данные. Допустим, вы обновили столбец, и теперь он содержит 900 символов. Возможно, что в текущем блоке нет места для расширения varchar. В этом случае механизм БД должен перенести строку в другой блок и сделать указатель в исходном блоке на новую строку в новом блоке. Теперь для чтения этих данных движку БД необходимо будет прочитать 2 блока. Никто не может однозначно сказать, что varchar или char лучше. Есть место для компромисса по времени и рассмотрения того, будут ли обновляться данные, особенно если есть большая вероятность, что они будут расти.
Я думаю, в вашем сообщении есть опечатка - разве varchar2 (1000) не должен быть CHAR (1000)?
Это классический компромисс между пространством и производительностью.
В MS SQL 2005 Varchar (или NVarchar для языков, требующих двух байтов на символ, например китайский) имеют переменную длину. Если вы добавите строку после того, как она была записана на жесткий диск, данные будут размещены в несоответствующем месте исходной строки и приведут к фрагментации ваших файлов данных. Это повлияет на производительность.
Итак, если пространство не является проблемой, тогда Char лучше для производительности, но если вы хотите уменьшить размер базы данных, тогда лучше использовать varchars.
Я думаю, что в вашем случае, вероятно, нет причин не выбирать Варчара. Это дает вам гибкость, и, как было отмечено рядом респондентов, производительность теперь такова, что, за исключением очень специфических обстоятельств, мы, простые смертные (в отличие от администраторов баз данных Google), не заметим разницы.
Когда дело доходит до типов БД, стоит отметить интересную вещь: sqlite (популярная мини-база данных с довольно впечатляющей производительностью) помещает все в базу данных в виде строки и набирает на лету.
Я всегда использую VarChar и обычно делаю его намного больше, чем мне может потребоваться. Например. 50 для имени, как вы говорите, почему бы просто не на всякий случай.
Многие люди отмечали, что использование CHAR дает некоторые преимущества, если вы знаете точную длину значения. Но хотя сохранение штатов США в виде CHAR (2) сегодня прекрасно, когда вы получаете сообщение от продаж, что «мы только что совершили нашу первую продажу в Австралию», вы попадаете в мир боли. Я всегда присылаю, чтобы переоценить, сколько, по моему мнению, должно быть полей, вместо того, чтобы делать «точное» предположение для покрытия будущих событий. VARCHAR даст мне больше гибкости в этой области.
CHAR занимает меньше места для хранения, чем VARCHAR, если все значения данных в этом поле имеют одинаковую длину. Теперь, возможно, в 2009 году база данных 800 ГБ будет такой же для всех целей и задач, как 810 ГБ, если вы преобразовали VARCHAR в CHAR, но для коротких строк (1 или 2 символа), я бы сказал, что CHAR по-прежнему является отраслевой "лучшей практикой".
Теперь, если вы посмотрите на широкий спектр типов данных, которые большинство баз данных предоставляют даже для одних целых чисел (bit, tiny, int, bigint), ЕСТЬ причины выбрать один из них. Простой выбор bigint каждый раз на самом деле немного игнорирует цели и способы использования поля. Если поле просто представляет возраст человека в годах, bigint будет излишним. Это не обязательно «неправильно», но это неэффективно.
Но это интересный аргумент, и поскольку базы данных со временем улучшаются, можно утверждать, что CHAR vs VARCHAR становятся менее актуальными.
Фрагментация. Char резервирует место, а VarChar - нет. Разделение страниц может потребоваться для размещения обновления до varchar.
Из-за множества других факторов при обновлении столбца CHAR может произойти разделение страницы.
Использование CHAR (NCHAR) и VARCHAR (NVARCHAR) приводит к различиям в способах хранения данных сервером базы данных. Первый вводит завершающие пробелы; Я столкнулся с проблемой при использовании его с оператором LIKE в функциях SQL SERVER. Поэтому я должен постоянно использовать VARCHAR (NVARCHAR).
Например, если у нас есть таблица ТЕСТ (ID INT, статус CHAR (1)), и вы пишете функцию для вывода списка всех записей с некоторым конкретным значением, например следующим:
CREATE FUNCTION List(@Status AS CHAR(1) = '')
RETURNS TABLE
AS
RETURN
SELECT * FROM TEST
WHERE Status LIKE '%' + @Status '%'
В этой функции мы ожидаем, что при установке параметра по умолчанию функция вернет все строки, но на самом деле это не так. Измените тип данных @Status на VARCHAR, чтобы решить проблему.
Это также можно изменить с помощью ansi_padding Как получаются значения
Я бы НИКОГДА не использовал символы. У меня были эти дебаты со многими людьми, и они всегда вспоминают устаревшее клише, что чар быстрее. Ну я говорю, насколько быстрее? О чем мы здесь говорим, миллисекундах, секундах и если да, то сколько? Вы говорите мне, что, поскольку кто-то утверждает, что это на несколько миллисекунд быстрее, мы должны внести в систему тонны трудно исправляемых ошибок?
Итак, вот некоторые проблемы, с которыми вы можете столкнуться:
Каждое поле будет дополнено, так что вы навсегда получите код с RTRIMS повсюду. Это также огромная трата дискового пространства для более длинных полей.
Теперь предположим, что у вас есть типичный пример поля char, состоящего только из одного символа, но это поле является необязательным. Если кто-то передает в это поле пустую строку, оно становится одним пробелом. Поэтому, когда другое приложение / процесс запрашивает его, они получают один-единственный пробел, если они не используют rtrim. У нас были XML-документы, файлы и другие программы, отображающие только один пробел в необязательных полях и нарушающие работу.
Итак, теперь вы должны убедиться, что вы передаете в поле char нули, а не пустую строку. Но это НЕ правильное использование null. Вот использование null. Допустим, вы получили файл от поставщика.
Имя | Пол | Город
Боб || Лос-Анджелес
Если пол не указан, вы вводите в таблицу Боб, пустую строку и Лос-Анджелес. Теперь предположим, что вы получили файл, и его формат изменился, а пол больше не включен, но был в прошлом.
Имя | Город
Боб | Сиэтл
Что ж, поскольку пол не включен, я бы использовал null. Варчары поддерживают это без проблем.
Char, с другой стороны, другое дело. Вы всегда должны отправлять null. Если вы когда-нибудь отправите пустую строку, вы получите поле с пробелами.
Я мог бы продолжать и продолжать со всеми ошибками, которые мне приходилось исправлять с помощью символов и примерно за 20 лет разработки.
Не уверен, что это ОТЛИЧНЫЙ ответ, поскольку ENUM обычно имеет гораздо больше смысла, хотя я не уверен, насколько широко поддерживается этот тип (за пределами MySQL).