Влияние на производительность размеров MySQL VARCHAR

45

Есть ли разница в производительности в MySQL между размерами varchar? Например, varchar(25)и varchar(64000). Если нет, есть ли причина не объявлять все varchars с максимальным размером только для того, чтобы убедиться, что вам не хватит места?

BENV
источник
3
+1 этот вопрос применяется аналогично всем СУБД. По моим наблюдениям, многие размеры varchar имеют тенденцию к росту.
bernd_k
5
Не MySQL, но это сообщение в блоге Depesz может ответить на ваш вопрос о PostgreSQL .
ксенотеррацид

Ответы:

29

Вы должны понять компромиссы использования CHAR против VARCHAR

С полями CHAR вы выделяете именно то, что получаете. Например, CHAR (15) выделяет и хранит 15 байтов, независимо от того, какие символы вы размещаете в поле. Работа со строками проста и понятна, поскольку размер поля данных полностью предсказуем.

С полями VARCHAR вы получите совершенно другую историю. Например, VARCHAR (15) фактически выделяет динамически до 16 байтов, до 15 для данных и, по крайней мере, 1 дополнительный байт для хранения длины данных. Если у вас есть строка 'hello' для хранения, которая будет занимать 6 байтов, а не 5. Во всех случаях при обработке строк всегда должна выполняться проверка длины.

Компромисс становится более очевидным, когда вы делаете две вещи:
1. Хранение миллионов или миллиардов строк.
2. Индексирование столбцов, которые являются CHAR или VARCHAR.

ТОРГОВЛЯ № 1

Очевидно, что VARCHAR обладает преимуществом, поскольку данные переменной длины будут создавать меньшие строки и, следовательно, меньшие физические файлы.

ТОРГОВЛЯ № 2

Поскольку поля CHAR требуют меньших манипуляций со строками из-за фиксированной ширины поля, поиск индекса по полю CHAR в среднем на 20% быстрее, чем поиск полей VARCHAR. Это не какая-то догадка с моей стороны. Книга MySQL Database Design and Tuning провела нечто удивительное на столе MyISAM, чтобы доказать это. Пример в книге сделал что-то вроде следующего:

ALTER TABLE tblname ROW_FORMAT=FIXED;

Эта директива заставляет VARCHAR вести себя как CHAR. Я сделал это на своей предыдущей работе в 2007 году, взял таблицу на 300 ГБ и ускорил поиск индекса на 20%, не меняя ничего другого. Он работал как опубликовано. Тем не менее, он дал таблицу почти в два раза больше, но это просто возвращает к компромиссу № 1.

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

SELECT * FROM tblname PROCEDURE ANALYSE();

Это будет проходить по всей таблице и рекомендовать определения столбцов для каждого столбца на основе содержащихся в нем данных, минимальных значений полей, максимальных значений полей и т. Д. Иногда вам просто нужно руководствоваться здравым смыслом при планировании CHAR против VARCHAR. Вот хороший пример:

Если вы храните IP-адреса, маска для такого столбца должна содержать не более 15 символов (xxx.xxx.xxx.xxx). Я бы сразу перешел к CHAR (15), потому что длины IP-адресов не будут сильно меняться, а сложность манипулирования строками будет контролироваться дополнительным байтом. Вы все еще можете выполнить АНАЛИЗ ПРОЦЕДУРЫ () для такого столбца. Может даже порекомендовать VARCHAR. В этом случае мои деньги все еще будут на CHAR, а не на VARCHAR.

Проблемы CHAR и VARCHAR могут быть решены только путем правильного планирования. С большой силой приходит большая ответственность (клише, но это правда)

RolandoMySQLDBA
источник
4
Если вы храните IP-адреса, я не вижу причин хранить их как что-либо кроме int. Это все IP-адрес. Многие языки имеют какую-то функцию ip2int. Если вы хотите удобство вызова из командной строки, нетрудно создать хранимую процедуру для преобразования ABCD: pow (256,3) + b pow (256,2) + c * 256 + d
atxdba
1
Более того, я думаю, у mysql есть своя собственная функция ip2int: INET_ATON
atxdba
3
@atxdba: Смысл моего ответа - использовать CHAR против VARCHAR. Я просто использую IP в качестве примера, потому что его размер строки строки ближе к 15. Таким образом, округление стабильного размера CHAR в пользу VARCHAR является лишь примером ради самого вопроса. Ваш комментарий о лучших способах представления IP-адресов вполне обоснован и имеет смысл.
RolandoMySQLDBA
CHAR (15) выделяет 15 символов , а не байтов . Для utf8 это 45 байтов .
Рик Джеймс
2
Хотя это хороший ответ о сравнении CHAR / VARCHAR, вопрос был о разных размерах VARCHAR.
Коллекционер
13

Ответ на это на самом деле довольно сложный. Краткая версия: есть разница .

  1. При создании временных таблиц для фильтрации результатов (например, GROUP BYоператоров) будет выделена полная длина.

  2. Проводной протокол (отправка строк клиенту), вероятно, выделит большую длину.

  3. Механизм хранения может / не может реализовать правильный varchar.

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

Морган Токер
источник
Стоит отметить. MySQL 5.7 может упаковать значения в буфер сортировки (переменной длины). Более подробно объяснено
Морган Токер
9

Большинству ответов в этой теме 5 лет, они написаны до того, как InnoDB и utf8 были значениями по умолчанию. Итак, позвольте мне начать все сначала ...

Когда запросу нужна внутренняя временная таблица, он пытается использовать MEMORYтаблицу. Но ПАМЯТЬ нельзя использовать, если

  • TEXT/ BLOBстолбцы извлекаются, даже не TINYTEXT.
  • VARCHAR больше некоторой суммы, вероятно, 512 в текущей версии.

Также обратите внимание, что VARCHARsпревращаются в CHARs. Таким образом, VARCHAR(255)с CHARACTER SET utf8расширением до 765 байтов, независимо от того, что находится в столбце. Затем это может быть вызвано:

  • Если MEMORYтаблица становится больше, чем либо, max_heap_table_size либо tmp_table_size она будет преобразована в MyISAM и потенциально попадет на диск.

Так что, VARCHAR(25)скорее всего, останется MEMORY, значит, будет быстрее. (255)не так хорошо, а (64000)плохо.

(В будущем временные таблицы, вероятно, будут InnoDB, и часть этого ответа потребуется пересмотреть.)

Рик Джеймс
источник
6

Столбец varchar такого размера повышает вероятность использования запросов во всей таблице во временных таблицах. Согласно книге High Performance MySQL. Когда оптимизатор пытается определить, может ли он выполнить этот запрос в памяти или ему нужна временная таблица, он смотрит на размер строки на основе определения таблицы, то есть для скорости он не пытается увидеть, сколько из 64К символов вы на самом деле используете. Вот почему авторы рекомендуют не расширять это определение за пределы фактических возможных значений, которые будут указаны в столбце. Очевидно, что если вы настроите себя на большее количество запросов, поступающих во временные таблицы (даже если фактический размер данных может уместиться в ОЗУ), вы теперь понесли штрафы за ввод-вывод, которых можно было бы избежать.

TechieGurl
источник
Это очень свежая перспектива. Если это книга, на которую вы ссылаетесь ( amazon.com/MySQL-High-Availability-Building-Centers/dp/… ), укажите номер страницы книги в своем ответе, потому что я хотел бы прочитать это. +1 !!!
RolandoMySQLDBA
Глупый я… Высокая ЭФФЕКТИВНОСТЬ, а не доступность: amazon.com/High-Performance-MySQL-Optimization-Replication/dp/…… номер страницы 236/237 Это объясняет, как щедрость в определении столбца varchar может быть неразумной. Имейте в виду, что эта книга была написана еще тогда, когда только что вышла версия 5.1. В следующем году выйдет третье издание, включающее все БОЛЬШИЕ изменения в 5.5, так что, возможно, это изменится :)
TechieGurl
Страница 236 упоминает сопоставление, принадлежащее определенным наборам символов. Это могло бы быть немного неприятно для VARCHAR. На странице 237 в настройках связи клиент-сервер, а также на рис. 5-5 на стр. 238 показана другая причина. Процесс перевода наборов символов взад и вперед. Опять другое неприятное приключение для VARCHAR.
RolandoMySQLDBA
Для пояснения, хотя в этом разделе не говорится прямо, что MySQL пойдет на создание размера, мы знаем, что когда для операции требуется временная таблица, эта таблица находится в MEMORY Engine, а THAT всегда хранит строковые типы в чанках исправлений, поэтому щедрый определение может привести к тому, что необходимая временная таблица MEMORY попадет на диск, а не останется в ОЗУ
TechieGurl
@RolandoMySQLDBA. Да ... это тоже ... сортировка также становится фактором здесь (особенно если вы используете UTF-8 и у вас есть нелатинские символы), и все это просто убивает вас при работе с таблицей
подсистемы
5

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

Jcolebrand
источник
3

убедитесь, что у вас нет места

Эта фраза подразумевает, что вы задаете вопрос, потому что не уверены в данных, которые будете хранить в базе данных. Если это правда, вам будет полезно выяснить это как можно скорее, потому что это понадобится вам для планирования загрузки. Например, если вы получаете элементы данных с 7000 символов, вам нужно знать об этом, поскольку это повлияет на производительность любой СУБД.

Тем не менее, я предпочитаю иметь размеры столбцов, связанные с ожидаемым содержанием. Например, номер телефона вряд ли будет длиннее 50 символов, даже если вы включите код страны и добавочный номер. Аналогичным образом почтовый индекс, скорее всего, будет состоять из 20 символов или менее.

Ларри Коулман
источник