Типы строк MySQL представлены в двух вариантах: один без метки набора символов и один с меткой набора символов.
Строка фиксированной длины, дополненная пробелами в конце, - это CHAR (n). Тип соответствия, у которого нет метки набора символов, - BINARY (n). Сохранение строки "hello" в CHAR(255) CHARSET utf8
займет 765 байт (строка, дополненная пробелами до полной длины, хранится как utf8, которая в худшем случае использует пространство 3 байта / символ, выделяющее 3 * 255 байт).
Строка переменной длины с одним или двумя байтами длины и без заполнения - VARCHAR ((n). Тип соответствия, у которого нет метки набора символов, - VARBINARY (n). Сохранение строки "hello" в VARCHAR(255) CHARSET utf8
будет занимает 6 байт (1 байт длины плюс 5 байт для фактического текста). Сохранение строки ク リ ス в том же типе займет 10 байт (1 байт длины плюс 3 символа, используя 3 байта на символ для их представления).
mysql> select hex('クリス'), length(hex('クリス'))/2 as bytes;
+--------------------+--------+
| hex('クリス') | bytes |
+--------------------+--------+
| E382AFE383AAE382B9 | 9.0000 |
+--------------------+--------+
1 row in set (0.02 sec)
Строка переменной длины с одним, двумя, тремя или четырьмя байтами длины - это TINYTEXT, TEXT, MEDIUMTEXT и LARGETEXT. Типы соответствия, у которых нет метки набора символов: TINYBLOB, BLOB, MEDIUMBLOB и LARGEBLOB.
TEXT / BLOB-подобный тип отличается от VARCHAR / VARBINARY-подобного типа тем, как и где хранятся данные, подробности о том, как TEXT / BLOB-подобные типы хранятся в InnoDB, см. В http://www.mysqlperformanceblog.com/2010/02/09/blob-storage-in-innodb/ по версии и настройкам ROW_FORMAT. Из соображений производительности вам нужна последняя версия таблиц InnoDB и "Barracuda".
MySQL не способен работать с любыми данными, размер которых превышает max_allowed_packet (по умолчанию: 1M), если вы не создадите сложные и интенсивно использующие память обходные пути на стороне сервера. Это дополнительно ограничивает то, что может быть сделано с TEXT / BLOB-подобными типами, и обычно делает тип LARGETEXT / LARGEBLOB бесполезным в конфигурации по умолчанию.
Для типов без метки набора символов (BINARY, VARBINARY и% BLOB%) MySQL будет принимать данные как полученные и записывать их на диск. Для типов с меткой набора символов MySQL будет смотреть на то, что вы объявили в качестве набора символов клиента для сервера с SET NAMES
, и что такое метка набора символов, определенная в столбцах. Затем он преобразует из набора символов соединения в набор символов столбца и записывает преобразованные данные. Вы можете проверить это с помощью функции HEX (), например, SELECT HEX(str) FROM t WHERE id = ...
.
При поиске объявленный набор символов с SET NAMES
может отличаться от того, который был во время записи. MySQL снова проверит метку набора символов столбцов относительно набора символов, объявленного для этого подключения, и при необходимости преобразует в набор символов подключения.
Потеря производительности для этого преобразования в любом случае незначительна по сравнению со временем, затрачиваемым на дисковый ввод-вывод, понесенный для таких данных, в любом случае, для производительности вряд ли имеет значение, какой тип вы выберете. Вместо этого действует правило: выберите тип с меткой набора символов, если вы работаете с текстовыми данными, и тип без, если вы не работаете.
Часто задаваемый вопрос: должен ли я выбрать CHAR или VARCHAR (BINARY или VARBINARY соответственно)?
Для InnoDB ответ всегда: выберите тип данных переменной длины. В InnoDB нет никаких преимуществ с точки зрения производительности, но существует огромный штраф, если вы выбираете тип данных фиксированной длины, а затем не используете все пространство в нем. Кроме того, строковые типы SQL фиксированной длины имеют действительно странные правила, касающиеся заполнения и обрезки с пробелами в конце, которые вы, вероятно, не потрудитесь изучить. Для MySQL случай может быть другим, но почти никогда не бывает.
Еще один связанный вопрос: я должен выбрать VARCHAR или TEXT для моих строк (VARBINARY или BLOB, соответственно)?
Ответом для этого является использование последней версии InnoDB, таблиц формата Barracuda, а затем TEXT / BLOB.Причина этого подробно объясняется в http://www.mysqlperformanceblog.com/2011/04/07/innodb-row-size-limitation/.. Результат этого: с VARCHAR или TEXT / BLOB в формате pre-Barracuda вы рискуете переполнить ограничение размера строки InnoDB, если у вас слишком многоих в одну строку.
И, наконец: Должен ли я хранить файлы / изображения / другие большие большие двоичные объекты или текстовые данные в базе данных?
Ответ таков: обычно нет.Обслуживание файлов из базы данных (http://mysqldump.azundris.com/archives/36-Serving-Images-From-A-Database.html) - дорогостоящая операция по сравнению с обслуживанием файлов из файловой системы. Если это вообще возможно, вы захотите сделать это вместо этого. Есть способ обойти это, http://www.blobstreaming.org/, но это продвинутая технология, которая требует полного контроля над средой выполнения, чего никогда не бывает в размещенной среде.
В заключение: в данных нет типов данных переменной длины.Таблицы механизма MEMORY. Так что если вы видите «использование временного» в выводе EXPLAIN
, это означает, что
- VARCHAR преобразуется в CHAR в этой временной таблице
- VARBINARY преобразуется вBINARY
Если временная таблица этого процесса становится больше, чем tmp_table_size ИЛИ max_heap_table_size, она на лету преобразуется в формат MyISAM и отправляется на диск.
Пример: вы определяетеКласс * Ruby Active Record User
содержит десять полей, помеченных как :string
. Каждое из них заканчивается VARCHAR(255) CHARSET utf8
в вашей таблице Users
,
В другом месте вашей кодовой базы Users
используется таким образом, что включает план using temporary
.Вы мгновенно умираете в дисковых операциях под нагрузкой, потому что каждая строка таблицы Users
теперь использует как минимум 7650 байт в MEMORY, большинство из которых являются пробелами, используемыми в качестве заполнения.Это вынуждает временную таблицу преобразовываться в MyISAM и записывать на диск.
- любой тип% TEXT% или% BLOB% не может быть представлен в MEMORY, поэтому временная таблица отправляется на диск как MyISAM, даже еслион был бы достаточно мал для хранения в памяти в соответствии с указанными выше ограничениями.
Это означает, что любой запрос с типом TEXT или BLOB и планом с «использованием временного» необходимо переписатьво избежание попадания временных таблиц на диск.