Имеет ли VARCHAR
смысл декларировать размер для производительности? Есть ли разница (по скорости) между VARCHAR(50)
и VARCHAR(255)
? Или определение длины - это логика / ограничение дизайна?
mysql
database-design
Sonique
источник
источник
Ответы:
Это очень распространенный «вопрос экзамена / интервью». Я отвечу так хорошо, как я могу:
В стандартных форматах строк для InnoDB и MyISAM (динамический / компактный) a
VARCHAR(50)
и aVARCHAR(255)
сохранят текст строки одинаковым образом - 1 байт для длины и фактическую строку с 1-4 байтами на символ (в зависимости от кодировки и фактический символ хранится).На самом деле, если я правильно помню, я вспоминаю, как кто-то изменял словарь данных с помощью шестнадцатеричного редактора, чтобы изменить что-то вроде a
VARCHAR(50)
на aVARCHAR(100)
, чтобы это можно было сделать динамически (обычно это требует реконструкции таблицы). И это было возможно, потому что это изменение не повлияло на фактические данные.Это не так
VARCHAR(256)
, потому что тогда всегда требуется 2 байта (как минимум) для длины.Итак, это значит, что мы всегда должны делать
VARCHAR(255)
, не так ли? Нет. Есть несколько причин.В то время как InnoDB может хранить varchar динамически, это не относится к другим движкам. MyISAM имеет фиксированный формат строки, а таблицы MEMORY всегда имеют фиксированный размер. Должны ли мы заботиться о тех других двигателях? Да, мы должны, потому что, даже если мы не используем их напрямую, таблицы MEMORY очень часто используются для промежуточных результатов (временных таблиц в памяти) , и, поскольку результаты не известны заранее, таблица должна быть создана с максимальным размером возможно -
VARCHAR(255)
если это наш тип. Если вы можете думать о потраченном впустую пространстве, если мы используем'utf8' charset
кодировку MySQL , MEMORY зарезервирует 2 байта для длины + 3 * 255 байтов на строку(для значений, которые могут занимать всего несколько байтов в InnoDB). Это почти 1 ГБ на 1 миллионном столе - только для VARCHAR. Это не только вызывает ненужную нагрузку на память, но может провоцировать действия, выполняемые на диске, потенциально замедляя его в тысячи раз. Все это из-за неправильного выбора определенного типа данных (независимо от содержимого).Это имеет некоторые последствия и для InnoDB. Размер индекса ограничен 3072 байтами, а индексы из одного столбца - до 767 байтов *. Таким образом, весьма вероятно, что вы не сможете полностью проиндексировать
VARCHAR(255)
поле (при условии, что вы используете utf8 или любую другую кодировку переменной длины).Кроме того, максимальный встроенный размер строки для InnoDB составляет половину страницы (около 8000 байт), а поля переменной длины, такие как BLOB или varchar, можно хранить вне страницы, если они не помещаются на полстранице . Это имеет некоторые последствия для производительности (иногда хорошие, иногда плохие, в зависимости от использования), которые нельзя игнорировать. Это вызвало некоторые странности между форматами COMPACT и DYNAMIC. См., Например: ошибка 1118: слишком большой размер строки. utf8 innodb
И последнее, но не менее важное, как напомнил мне @ypercube, может потребоваться более 1 байта для длины, даже если вы используете
VARCHAR(255)
, потому что определение в символах, а длина хранит байты. Например,REPEAT('ñ', 255)
имеет больше 2 ^ 255 байтов в utf8, поэтому для хранения его длины потребуется более 1 байта:Таким образом, общий совет - использовать наименьший возможный тип , потому что в противном случае он может создать проблемы с производительностью или управлением. A
VARCHAR(100)
лучше чемVARCHAR(255)
(хотя aVARCHAR(20)
будет лучше), даже если вы не знаете точную длину. Постарайтесь быть консервативным, потому что, если таблица не слишком большая, вы всегда можете изменить определение позже.Обновление: поскольку популярность строк переменной длины, например, с использованием смайликов, растет, Oracle стремится к повышению производительности в этих случаях. В последних версиях MySQL (5.6, 5.7) InnoDB был установлен в качестве механизма по умолчанию как для внутренних, так и для явных временных таблиц, что означает, что поля переменной длины теперь являются гражданами первого класса. Это означает, что может быть меньше причин иметь очень ограниченную длину символов (но они все еще существуют).
(*) Второе обновление : large_prefix_index теперь включено по умолчанию в последних версиях MySQL (8.0), но это все еще верно для более старых версий или если вы используете медленный формат файлов / строк innodb (отличный от динамического или сжатого), но теперь по умолчанию индексы одного столбца могут быть до этих 3072 байтов.
источник
Забудьте о 1-байтовом префиксе
VARCHARs
.Вопрос о 255 задавался и отвечался много раз.
VARCHARs
может привести к провалуCREATE TABLE
.MEMORY
таблицы, аVARCHARs
превращаться вVARCHAR
. Это означает, например, чтоVARCHAR(255) CHARACTER SET utf8mb4
требуется фиксированная длина 1020 байтов. (Это не удастся, и выродится в использование MyISAM.)Итог: не используйте вслепую 255 (или 256); делать то, что имеет смысл для схемы.
источник