Важность длины varchar в таблице MySQL

112

У меня есть таблица MySQL, в которой строки вставляются динамически. Поскольку я не могу быть уверен в длине строк и не хочу, чтобы они обрезались, я делаю их varchar (200), который обычно намного больше, чем мне нужно. Есть ли большой удар по производительности, если дать полю varchar намного большую длину, чем необходимо?

Брайан
источник
VARCHAR(255) utf8mb4Размер таблицы с одним индексированным столбцом с ~ 150 тыс. Строк составляет 11,5 МБ. Таблица с VARCHAR(48) utf8mb4индексированным столбцом с теми же данными (максимальная длина 46 символов) занимала 4,5 МБ. Не особо большая разница в запросах, индексируется. Но это добавляется к вводу-выводу запросов и таким вещам, как резервное копирование базы данных.
Code4R7

Ответы:

59

Нет, в том смысле, что если значения, которые вы храните в этом столбце, всегда (скажем) меньше 50 символов, столбец объявлен как varchar(50)или varchar(200)имеет такую ​​же производительность.

Алекс Мартелли
источник
9
Не совсем так. См. Ответ Билла Карвина
hejdav 05
5
Я думаю, что такой ответ должен поддерживаться документами, тестами или чем-то подобным.
Gokhan Sari
301

Есть одно возможное влияние на производительность: в MySQL временные таблицы и MEMORYтаблицы хранят VARCHARстолбец как столбец фиксированной длины, дополненный до максимальной длины. Если вы проектируете VARCHARстолбцы, намного превышающие максимальный размер, который вам нужен, вы потребляете больше памяти, чем необходимо. Это влияет на эффективность кеширования, скорость сортировки и т. Д.

Билл Карвин
источник
33
+1. Мне также кажется, что некоторые драйверы JDBC выделяют достаточно места для максимального размера при настройке буферов для извлечения строк. Излишне говорить, что это вызывает сильную тревогу и скрежет зубов, когда какой-то клоун только что сделал варчар (50000) на случай, если у кого-то действительно большая фамилия :-)
paxdiablo
21
+1. Это важное воздействие, и я считаю, что это настоящий ответ на этот вопрос.
Emre Yazici
6
Этот ответ и принятый ответ необходимы для понимания правильного ответа на OP.
kd8azz
2
Фактически, когда такая MEMORYтаблица считается слишком большой, она записывается на диск, что приводит к значительному снижению производительности.
Timo
1
В этом ответе можно указать, для каких механизмов хранения он верен (я отмечаю, что dev.mysql.com/doc/refman/8.0/en/… указывает, что временные таблицы всегда являются InnoDB начиная с MySQL 8; это что-то меняет?) , и со ссылками на документы, подтверждающие сделанные в нем утверждения. Судя по тому, что я видел из ваших результатов на Stack Exchange, я уверен, что вы были правы, когда написали это, но все могло измениться, и ссылки послужили бы хорошим примером для других и помогли бы научить остальных из нас находить такая информация для себя.
Марк Эмери
14

VARCHAR идеально подходит для описываемой вами ситуации, потому что он означает «переменный символ» - предел, основанный на вашем примере, будет составлять 200 символов, но все меньше допускается и не заполняет выделенный размер столбца.

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

Для получения дополнительной информации о сравнении типов данных MySQL CHAR и VARCHAR см. Эту ссылку .

OMG Пони
источник
1
всем, кто интересуется хранилищем MySQL (о CHAR и VARCHAR), следует прочитать ссылку, указанную в этом ответе. Спасибо!
Паскаль
14

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

В вашем случае есть много утечек производительности, с которыми вы можете столкнуться: большие объединения почти невозможны с длинными varcharстолбцами. Индексирование этих столбцов - настоящий убийца. Ваш диск должен хранить данные. Одна страница памяти может содержать меньше строк, и сканирование таблиц будет намного медленнее. Также здесь вряд ли поможет кеш запросов.

Вы должны спросить себя: сколько пластинок может происходить в год? Какая средняя длина? Действительно ли мне нужно более 200 символов, или я могу уловить это в моем интерфейсе приложения, даже сообщив пользователям о максимальной длине? Могу ли я разделить таблицу на узкую для быстрого индексирования и сканирования и на другую для хранения дополнительных, менее часто используемых данных увеличивающегося размера? Могу ли я ввести возможные данные varchar в категории и таким образом извлечь часть данных в несколько столбцов меньшего размера, возможно, типа int или bool и таким образом сузить столбец varchar?

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

слегка подталкивать локтем
источник
+1 за список вариантов дизайна и изучение влияния. Очень полезно и для моего вопроса. stackoverflow.com/q/12083089/181638
Асад Эбрагим,
5
Есть ли какое-либо влияние на производительность от установки высокой максимальной длины, или производительность определяется только фактическим размером?
poolie
5

Производительность? Нет. Дисковое хранилище? Да, но это дешево и в изобилии. Если ваша база данных не вырастет до терабайтного масштаба, вы, вероятно, в порядке.

duffymo
источник
Странно, что этот ответ был отвергнут через шесть лет после публикации, а остальные - нет. Кажется мстительным и мелочным. В этом ответе нет ничего неправильного. Модераторы?
duffymo
1
Как было сказано, это действительно влияет на производительность. Кроме того, дисковое хранилище тоже не является бесплатным. Более широкий столбец означает больше операций чтения / записи на диск (а доступ к диску медленный), а также более широкие индексы, что снижает их полезность. Обе вещи отрицательно влияют на производительность. Возможно, это ничтожно мало для небольшой базы данных, но в масштабе гигабайт / терабайт это определенно будет иметь значение, как вы говорите. Для таблицы из 100 регистров это не имеет значения.
Алехандро
5

Некоторые из вас ошибаются, полагая, что файл varchar(200)занимает на диске больше таблицы, чем файл varchar(20). Это не вариант. Только когда вы выходите за пределы 255 символов, mysql использует дополнительный байт для определения длины данных varcharполя.

DCH
источник
9
Не так для временных таблиц и MEMORYтаблиц.
Гонки легкости на орбите
4
Каждый раз, когда ваш запрос выбора использует временную таблицу (среди прочего, сгруппируйте и упорядочивайте по операциям), он преобразует varchar (200) в char (200), и производительность будет снижаться.
Джейми
1

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

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

Приводит ли varchar к снижению производительности из-за фрагментации данных?

Еще лучше, char vs varchar .

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

Ризван Кассим
источник
0

Являясь varchar, а не просто char, размер зависит от внутреннего поля, указывающего его фактическую длину и самой строки. Таким образом, использование varchar (200) не сильно отличается от использования varchar (150), за исключением того, что у вас есть возможность хранить больше.

И вы должны учитывать, что происходит при обновлении, когда строка растет. Но если это случается редко, тогда все будет в порядке.

Роб Фарли
источник
0

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

user2903114
источник
0

Вы должны попытаться просмотреть столбец varchar так же, как столбец char в большинстве сценариев, и установить длину консервативно. Вам не нужно всегда думать о модификаторе var как о чем-то, что влияет на принятие решения о максимальной длине. Это действительно следует рассматривать как подсказку производительности, а не то, что поставляемые строки будут иметь разную длину.

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

Если у вас есть varchar (255), у вас нет гарантии, что с точки зрения производительности он всегда будет вести себя иначе, чем char (255) при любых обстоятельствах.

Может показаться, что легко установить для него что-то вроде 255, 65535 и т. Д. В соответствии с рекомендациями, приведенными в руководстве о требованиях к хранению. Создается впечатление, что любое значение от 0 (да, это вещь) до 255 будет иметь такое же влияние. Однако это не то, что можно полностью гарантировать.

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

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

Вы должны убедиться, что запросы MySQL выдают ошибку, когда строка слишком длинная, а не усекается, чтобы, по крайней мере, вы знали, может ли она быть слишком короткой, по выбросам ошибок. Изменение размера столбцов для их увеличения или уменьшения может быть дорогостоящей операцией DDL, об этом следует помнить.

Также следует учитывать набор символов, когда важны длина и производительность. Длина относится к этому, а не к байтам. Например, если вы используете utf8 (не MB4), тогда varchar (255) действительно является varbinary (3 * 255). Трудно понять, как такие вещи действительно будут развиваться, не проводя тесты и не углубляясь в исходный код / ​​документацию. Из-за этого чрезмерная длина может иметь неожиданно завышенный удар. это касается не только производительности. Если вам однажды понадобится изменить набор символов столбца varchar на более крупный, то вы можете в конечном итоге достичь некоторого предела без обращения, если вы позволите присутствовать необоснованно длинным строкам, которых можно было бы избежать. Обычно это довольно узкая проблема, но она возникает,

Если окажется, что MAX (LENGTH (столбец)) всегда <64 (например, если было решено, что будет лимит на ввод, который не соответствует определению столбца), но у вас есть varchar (255), тогда есть хороший шанс, что вы будете использовать в четыре раза больше места, чем необходимо в некоторых сценариях.

Это может включать:

  • Разные двигатели, некоторые могут вообще игнорировать.
  • При размерах буфера, например при обновлении или вставке, может потребоваться выделить все 255 (хотя я не проверял исходный код, чтобы доказать это, это всего лишь гипотеза).
  • Индексы, это сразу станет очевидно, если вы попытаетесь создать составной ключ из множества столбцов varchar (255).
  • Промежуточные таблицы и, возможно, наборы результатов. Учитывая способ работы транзакций, не всегда возможно использовать фактическую максимальную длину строк в столбце в отличие от определенного предела.
  • Внутренняя прогнозная оптимизация может принимать в качестве входных данных максимальную длину.
  • Изменения в версиях реализации базы данных.

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

Когда вы не можете, если вы хотите сделать что-то вроде varchar (255) в случае сомнений, я рекомендую заняться наукой. Это может состоять в дублировании таблицы, уменьшении размера столбца var char, затем копировании данных в него из оригинала и просмотре размера данных индекса / строки (также индексируйте столбец, также попробуйте его как первичный ключ, который может вести себя иначе в InnoDB, поскольку строки упорядочены по первичному ключу). По крайней мере, так вы узнаете, повлияете ли вы на ввод-вывод, который, как правило, является одним из самых уязвимых узких мест. Тестировать на использование памяти сложнее, это сложно проверить полностью. Я бы порекомендовал протестировать возможные худшие случаи (запросы с большим количеством промежуточных результатов в памяти, проверка с объяснением для больших временных таблиц и т. Д.).

Если вы знаете, что в таблице не будет много строк, вы не собираетесь использовать столбец для объединений, индексов (особенно составных, уникальных) и т. Д., Тогда у вас, скорее всего, не будет много проблем.

jgmjgm
источник