MySQL: большой VARCHAR против текста?

847

У меня есть таблица сообщений в MySQL, которая записывает сообщения между пользователями. Помимо типичных идентификаторов и типов сообщений (все целочисленные типы) мне нужно сохранить фактический текст сообщения как VARCHAR или TEXT. Я устанавливаю входной предел в 3000 символов, что означает, что сообщения никогда не будут вставляться в БД, как это дольше.

Есть ли смысл использовать VARCHAR (3000) или TEXT? В написании VARCHAR (3000) есть что-то нелогичное. Я просматривал другие подобные сообщения о переполнении стека, но было бы неплохо получить представления, относящиеся к этому типу общего хранения сообщений.

Том
источник
28
Немного стар, но я пришел сюда, потому что столкнулся с проблемой, которая заставила меня задуматься над этим. В моем случае моя форма интерфейса была ограничена 2000 символами, но кодировка, неявная в моем методе хранения, кодировала международные символы в виде нескольких символов (что, очевидно, может составлять от 3 до 12 на символ). Так что мои 2000 внезапно становятся до 24000. Есть о чем подумать ...
Джеймс С
3
Я обнаружил, что текст для многих одновременных вставок значительно быстрее.
Рэй С.
1
@JamesS: utf8mb4 ...>. <
неделимый
10
@RickJames рассмотрите возможность размещения обновленного ответа, а не закрывайте вопрос
Иветт
3
@YvetteColomb - я добавил ответ. В основном я хотел бы избавиться от принятого ответа, потому что он устарел . Я пришел в Q & A, потому что кто-то цитировал неверную информацию, говоря: «754 голосов, так что это должно быть правильно». ОК, я также отредактировал Утвержденный ответ. (Хотя это кажется неправильным.)
Рик Джеймс

Ответы:

812
  • TEXTи BLOB может храниться вне таблицы с таблицей, имеющей только указатель на местоположение фактического хранилища. Где он хранится, зависит от многих вещей, таких как размер данных, размер столбцов, row_format и версия MySQL.

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

MindStalker
источник
149
+1: VARCHAR (хранится в строке) обычно быстрее, если данные часто извлекаются (включается в большинство запросов). Однако для большого объема данных, которые обычно не извлекаются (то есть не ссылаются ни на один запрос), может быть, лучше не хранить данные встроенными. Существует верхний предел размера строки для данных, хранящихся в строке.
spencer7593
22
@Pacerier: точное преимущество избежания «встроенного» хранения заключается в увеличении количества строк, которые могут быть сохранены в блоке, что означает, что строки таблицы занимают меньше блоков в буферном кеше InnoDB (меньший объем памяти) и означают меньше блоки для переноса на диск и с него (уменьшенный ввод / вывод). Но это только выигрыш в производительности, если на столбцы, хранящиеся вне строки, запросы не ссылаются. Если на большинство столбцов ссылаются на эти столбцы «вне строки», это преимущество в значительной степени испаряется. Встроенный является предпочтительным, если столбцы вписываются в максимальный размер строки и часто ссылаются.
spencer7593
232
«VARCHAR быстрее, когда размер разумный». Что такое «разумное» количество символов, 100? 1000? 100000?
Тим Петерсон
126
Этот ответ не является правильным для InnoDB. И VARCHAR, и BLOB / TEXT хранятся в строке с другими столбцами, если значение в данной строке соответствует размеру страницы (16 КБ, и каждая страница должна содержать не менее двух строк). Если строка слишком велика для этого, она переполняется на дополнительные страницы. См. Mysqlperformanceblog.com/2010/02/09/blob-storage-in-innodb для подробного объяснения.
Билл Карвин
15
@BillKarwin ... Если я правильно понять то , что не должно быть никакой разницы в производительности между varcharи blob/ textна InnoDB для небольших текстовых элементов? Так бы тогда разумно просто сделать все varcharна textтип и пусть DB управлять встроенным переполнением против?
ryvantage
475

Можете ли вы предсказать, как долго будет вводить пользователь?

УАКСНАК (Х)

Кейс: имя пользователя, адрес электронной почты, страна, тема, пароль


ТЕКСТ

Дело: сообщения, электронные письма, комментарии, форматированный текст, HTML, код, изображения, ссылки


MEDIUMTEXT

Дело: большие тела json, короткие и средние книги, csv-струны


LONGTEXT

Кейс: учебники, программы, файлы лет журналов, Гарри Поттер и кубок огня, ведение научных исследований

Майкл Дж. Калкинс
источник
8
Предсказуемость действительно побочный элемент здесь. Это на самом деле максимальная ожидаемая длина, которая должна быть решающим фактором. Элементы, которые вы упоминаете как более предсказуемые, только так, потому что они короче, чем другие.
Эндрю Барбер
30
@ Andrew-Barber Это моя точка зрения, хотя. Все остальные посты хорошо объясняют различия, но не ситуации, когда вам действительно приходится выбирать между ними. Я пытался указать, что использование varchar для предсказуемо короткого - это хороший выбор, а использование текста для произвольно длинного - хороший выбор.
Майкл Дж. Калкинс
1
Если все столбцы короткие и предсказуемые (например, MAC-адрес, IMEI и т. Д. - это вещи, которые никогда не меняются), то используйте столбцы CHAR, и вы можете установить фиксированный размер строки, что должно значительно ускорить процесс при использовании MyISAM, возможно, также InnoDb, хотя я не уверен в этом.
Мэтт
1
@ MichaelJ.Calkins То, что произошло в MySQL 5.6. Теперь у вас также есть полнотекстовый поиск в InnoDB. См dev.mysql.com/doc/refman/5.6/en/fulltext-search.html
PhoneixS
7
Пределы символов: TINYTEXT: 255; ТЕКСТ: 65 535; MEDIUMTEXT: 16 777 215; LONGTEXT: 4,294,967,29.
Виктор Стоддард
219

Просто чтобы уточнить лучшие практики:

  1. Текстовые сообщения почти всегда должны храниться в формате TEXT (в конечном итоге они будут произвольно длинными)

  2. Строковые атрибуты должны храниться как VARCHAR (имя пользователя, тема и т. Д.).

Я понимаю, что у вас есть лимит внешнего интерфейса, который хорош, пока его нет. * ухмылка * Хитрость заключается в том, чтобы рассматривать БД отдельно от приложений, которые к ней подключаются. То, что одно приложение накладывает ограничение на данные, не означает, что данные изначально ограничены.

Что в самих сообщениях заставляет их никогда не превышать 3000 символов? Если это просто произвольное ограничение приложения (скажем, для текстового поля или чего-то еще), используйте TEXTполе на уровне данных.

Джеймс
источник
Что значит «что хорошо, пока это не так»? Что означает «не»?
Пейсер
7
@Pacerier Чтобы дать вам пример «не», о котором Джеймс, скорее всего, думает: возьмем, к примеру, Twitter, который до недавнего времени имел ограничение в 140 символов на ПМ. Они решили, что это больше не имеет смысла, и решили полностью устранить этот предел. Если бы они не думали об этом заранее (что я вполне уверен, что они, вероятно, сделали ...), они бы столкнулись со сценарием, описанным выше.
PaulSkinner
9
Я просто добавляю нашу новую базу данных, и я предположил, что никто не сможет поместить более 2000 символов в наши крошечные поля для комментариев, а затем, как отмечает Джеймс, сегодня вечером это внезапно "не было хорошо", потому что пользователь пропустил очень правильный комментарий, который был длиной 2600 символов. Я использовал varchar (2000), думая, что это не может продолжаться дольше, и я ошибался. так что да, это здорово, пока это не так. В нашем случае это заняло всего несколько дней. Приведенное ниже правило, Майкл Дж. Калкинс, думаю, я буду использовать с этого момента. текст для сообщений, комментариев.
Lizardx
1
@Pacerier "это здорово, пока не плохо". Другими словами, это работает почти все время и замечательно ... за исключением тех исключительных ситуаций, когда это не так здорово.
Ограниченное искупление
@Pacerier Еще один интересный пример упоминается в комментариях к выбранному ответу, в основном он имел ограничение внешнего интерфейса в 2000 символов, но введенные символы находились в кодовой странице, которая в действительности использовала больше байтов, чем обычные буквы, его базе данных потребовалось место для 24k символов только потому, что он должен был учитывать фактический размер байта вводимых символов.
RaptorX
32

Отказ от ответственности: я не эксперт по MySQL ... но это мое понимание проблем.

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

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

Майкл Андерсон
источник
38
Ограничение длины строки составляет 65 535 байт [ dev.mysql.com/doc/refman/5.0/en/column-count-limit.html ]. Если ваш столбец имеет кодировку utf8, это означает, что varcharстолбец из 3000 символов может занимать до 9000 байтов.
Ян Фабри
7
Символы UTF-8 могут иметь длину до 4 байт, поэтому я думаю, что вы имели в виду 12 000 байт (если только в MySQL нет какой-то вещи, которую я здесь не понимаю).
RayLu
13
@raylu UTF-8 MySQL является «поддельным UTF-8» в том смысле, что он поддерживает максимум 3 байта на символ, поэтому в MySQL UTF-8 нет способа напрямую хранить символы Юникода за плоскостью BMP. Это исправлено в MySQL 5.5.
Пейсер
2
Я считаю, что это утверждение действительно только для MyISAM. Я не могу найти точный источник, но я полагаю, что InnoDB хранит TEXTвстроенный в таблице также.
dotancohen
2
@dotancohen Я нашел здесь источник, объясняющий, что хранение данных переменной длины с использованием InnoDB может варьироваться (может храниться как внешне, так и внутри строки). mysqlserverteam.com/externally-stored-fields-in-innodb
KiX Ortillan
30

Краткий ответ: нет практического, производительности или хранения, разницы.

Длинный ответ:

По сути, нет никакой разницы (в MySQL) между VARCHAR(3000)(или любым другим большим пределом) и TEXT. Первый будет усекать до 3000 символов ; последний будет урезан до 65535 байт . (Я делаю различие между байтами и символами, потому что символ может занимать несколько байтов.)

Для меньших ограничений VARCHARесть некоторые преимущества TEXT.

  • «меньше» означает 191, 255, 512, 767 или 3072 и т. д., в зависимости от версии, контекста и CHARACTER SET.
  • INDEXesограничены в том, насколько большой столбец может быть проиндексирован. (767 или 3072 байта ; это зависит от версии и настроек)
  • Промежуточные таблицы, созданные комплексом SELECTs, обрабатываются двумя различными способами - MEMORY (быстрее) или MyISAM (медленнее). Когда задействованы «большие» столбцы, автоматически выбирается более медленная техника. (Значительные изменения ожидаются в версии 8.0; поэтому этот элемент марки может быть изменен.)
  • Относительно предыдущего элемента все TEXTтипы данных (в отличие от VARCHAR) переходят прямо к MyISAM. То есть TINYTEXTавтоматически генерируется для сгенерированных временных таблиц хуже, чем эквивалент VARCHAR. (Но это берет обсуждение в третьем направлении!)
  • VARBINARYэто как VARCHAR; BLOBэто как TEXT.

Опровержение других ответов

Исходный вопрос задал одну вещь (какой тип данных использовать); принятый ответ отвечал на что-то другое (внеплановое хранение). Этот ответ сейчас устарел.

Когда этот поток был запущен и получен ответ, в InnoDB было только два «формата строки». Вскоре после этого были введены еще два формата ( DYNAMICи COMPRESSED).

Место хранения для TEXTи VARCHAR()зависит от размера , а не от имени типа данных . Для обновленного обсуждения о включении / выключении хранения больших столбцов текста / больших двоичных объектов смотрите это .

Рик Джеймс
источник
1
Некоторое хорошее понимание здесь. Это должен быть принятый ответ.
Коста Контос
2
@KostaKontos - Спасибо за похвалу и исправление опечатки. Когда я увижу потребность в лучшем ответе, я добавлю ответ, даже если 8 лет и 800 голосов слишком поздно.
Рик Джеймс
7

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

(SELECT t2.* FROM t1, t2 WHERE t2.id = t1.id ORDER BY t1.id) 

временная таблица может потребоваться, и если VARCHARполе задействовано, оно преобразуется в CHARполе во временной таблице. Таким образом, если в вашей таблице указано 500 000 строк с VARCHAR(65000)полем, только в этом столбце будет использоваться 6,5 * 5 * 10 ^ 9 байт. Такие временные таблицы не могут быть обработаны в памяти и записаны на диск. Можно ожидать, что воздействие будет катастрофическим.

Источник (с метриками): https://nicj.net/mysql-text-vs-varchar-performance/ (Это относится к обработке TEXTvs VARCHARв «стандартном» (?) Механизме хранения MyISAM. Он может отличаться в других, например, InnoDB.)

Максимум
источник
3
InnoDB: то же самое относится к версии 5.7. В версии 8.0 временные значения varchar имеют переменную длину.
Рик Джеймс
3

Существует огромная разница между VARCHAR и TEXT. Хотя поля VARCHAR могут быть проиндексированы, поля TEXT - нет. Поля типа VARCHAR хранятся встроенными, а TEXT хранятся в автономном режиме, в записях фактически хранятся только указатели на данные TEXT.

Если вам нужно проиндексировать поле для более быстрого поиска, обновления или удаления, чем использовать VARCHAR, независимо от его размера. VARCHAR (10000000) никогда не будет таким же, как поле TEXT, потому что эти два типа данных различны по своей природе.

  • Если вы используете свое поле только для архивации
  • вы не заботитесь о скорости передачи данных
  • вы заботитесь о скорости, но вы будете использовать оператор "% LIKE%" в своем поисковом запросе, так что индексация не сильно поможет
  • Вы не можете предсказать предел длины данных

чем перейти к тексту.

Виктор Жорас
источник
Частично вводящая в заблуждение информация: столбцы TEXT не могут быть проиндексированы полностью. Когда вы включаете столбец TEXT в индекс, вы должны указать длину. Кроме того, VARCHAR не могут быть проиндексированы полностью в случае VARCHAR> 255, поскольку максимальный размер индекса равен длине.
eRadical
2

Varchar для небольших данных, таких как адреса электронной почты, в то время как Text для гораздо больших данных, таких как новостные статьи, Blob для двоичных данных, таких как изображения.

Производительность Varchar более высокая, поскольку он полностью запускается из памяти, но это не будет так, если данные слишком велики, как, varchar(4000)например ,.

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

BLOB-объект намного медленнее, поэтому используйте его только в том случае, если у вас нет таких данных, как 10000 изображений, которые будут стоить 10000 записей.

Следуйте этим советам для максимальной скорости и производительности:

  1. Используйте varchar для имени, названий, электронных писем

  2. Используйте текст для больших данных

  3. Отдельный текст в разных таблицах

  4. Используйте запросы левого соединения для идентификатора, такого как номер телефона

  5. Если вы собираетесь использовать Blob, примените те же советы, что и в текстовом.

Это приведет к тому, что запросы будут стоить миллисекунды для таблиц с данными> 10 МБ и гарантированным размером до 10 ГБ.

Creative87
источник