MySQL: Великий VARCHAR проти ТЕКСТУ?


845

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

Чи є обґрунтування для того, щоб їхати або з VARCHAR (3000), або з TEXT? Існує щось про те, щоб просто написати VARCHAR (3000), який відчуває себе дещо контрінтуїтивним. Я переглядав інші подібні публікації на стеку Overflow, але було б добре отримати перегляди, характерні для цього типу загального зберігання повідомлень.


27
Трохи старий, але я прийшов сюди, бо зіткнувся з проблемою, яка змусила мене задуматися над цим. У моєму випадку моя форма переднього аркуша була обмежена 2000 символами, але кодування, неявне в моєму способі зберігання, кодувало міжнародні символи як декілька символів (що, мабуть, може бути від 3 до 12 на символ). Тож моїх 2000 раптом стає до 24000. Щось подумати ...
James S

3
Я знайшов текст значно швидшим для багатьох одночасних вставок.
Рей С.

1
@JamesS: utf8mb4 ...>. <
нероздільний

10
@RickJames розглядає можливість опублікувати оновлену відповідь, а не закривати питання
Іветт,

3
@YvetteColomb - я додав відповідь. В основному я хотів би позбутися прийнятого відповіді, оскільки він застарів . Я прийшов до запитання, тому що хтось цитував невірну інформацію, кажучи: "754 відгуків, значить, це має бути правильно". Гаразд, я також відредагував схвалену відповідь. (Хоча це відчуває себе неправильно.)
Рік Джеймс

Відповіді:


811
  • TEXTі BLOB може зберігатися поза таблицею, якщо таблиця просто має вказівник на місце фактичного зберігання. Де він зберігається, залежить від багатьох речей, таких як розмір даних, розмір стовпців, рядок_формату та версія MySQL.

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


148
+1: VARCHAR (зберігається в рядку), як правило, швидше, якщо дані часто отримують (включаються в більшість запитів). Однак для великого обсягу даних, який зазвичай не отримується (тобто не посилається жодним запитом), може бути краще, щоб дані не зберігалися в рядку. Існує верхня межа розміру рядка для даних, що зберігаються в рядку.
spencer7593

21
@Pacerier: точна перевага від уникнення "вбудованого" зберігання - це збільшення кількості рядків, які можна зберігати в блоці, а це означає, що рядки таблиці займають менше блоків у кеш-пам'яті InnoDB (менший слід пам'яті), і означає менше блоки для передачі на диск і з нього (зменшений введення / вивід). Але це лише користь від продуктивності, якщо стовпці, що зберігаються "поза рядком", значною мірою не залежать від запитів. Якщо ці стовпці "поза рядком" посилаються на більшість запитів, користь значною мірою випаровується. Вбудований варіант є кращим, якщо стовпці вміщуються в максимальний рядковий розмір і на них часто посилаються.
spencer7593

231
"VARCHAR швидше, коли розмір розумний". Що таке "розумна" кількість символів, 100? 1000? 100 000?
tim peterson

125
Ця відповідь не є правильною для InnoDB. І VARCHAR, і BLOB / TEXT зберігаються в рядку з іншими стовпцями, якщо значення в заданому рядку відповідає розміру сторінки (16 КБ і кожна сторінка повинна містити щонайменше два рядки). Якщо рядок занадто великий для цього, він переливається на додаткові сторінки. Детальну інформацію див. У розділі mysqlperformanceblog.com/2010/02/09/blob-storage-in-innodb .
Білл Карвін

14
@BillKarwin ... Якщо я правильно розумію, не повинно бути різниці між продуктивністю varcharта blob/ textна InnoDB для невеликих текстових елементів? Так би тоді розумно просто зробити все varcharна textтип і нехай DB управляти вбудованим переповненням проти?
ryvantage

473

Чи можете ви передбачити, як довго триватиме введення користувача?

ВАРХАР (X)

Випадок: ім’я користувача, електронна адреса, країна, тема, пароль


ТЕКСТ

Випадок: повідомлення, електронні листи, коментарі, відформатований текст, html, код, зображення, посилання


MEDIUMTEXT

Корпус: великі тіла json, книги короткої та середньої довжини, рядки csv


ДОВГОТЕКСТ

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


7
Передбачуваність справді є побічним елементом. Фактично максимальна очікувана довжина повинна бути вирішальним фактором. Елементи, які ви згадуєте як більш передбачувані, є лише таким чином, оскільки вони коротші, ніж інші.
Ендрю Барбер

29
@ andrew-barber Це все-таки моя думка. Усі інші публікації добре пояснюють відмінності, але не про ситуації, коли вам потрібно зробити вибір між ними. Я намагався вказати, що використання varchar для передбачувано короткого є хорошим вибором, а використання тексту довільно довго - хороший вибір.
Майкл Дж. Калкінс

1
Якщо всі стовпці короткі та передбачувані (наприклад: MAC-адреса, IMEI тощо) - речі, які ніколи не змінюються), використовуйте стовпці CHAR, і ви можете зробити фіксований розмір рядка, який повинен значно пришвидшити, якщо використовувати MyISAM, можливо також InnoDb, хоча я не впевнений у цьому.
Метт

1
@ MichaelJ.Calkins Річ, що сталася в MySQL 5.6. Тепер у вас також є повнотекстовий пошук у InnoDB. Дивіться dev.mysql.com/doc/refman/5.6/uk/fulltext-search.html
PhoneixS

7
Обмеження символів: TINYTEXT: 255; ТЕКСТ: 65 555; МЕДІУМЕКСТ: 16 777 215; ДОВГОТЕКСТ: 4,294,967,29.
Віктор Стоддард

218

Просто для уточнення найкращої практики:

  1. Повідомлення у форматі тексту майже завжди повинні зберігатися як TEXT (вони в кінцевому підсумку є довільно довгими)

  2. Атрибути рядків повинні зберігатися як VARCHAR (ім'я користувача призначення, тема тощо).

Я розумію, що у вас є обмеження на передньому кінці, що чудово, поки його немає. * grin * Хитрість полягає в тому, щоб БД розглядалася як окрема від додатків, які до неї підключаються. Тільки тому, що одна програма ставить обмеження на дані, не означає, що дані суттєво обмежені.

Що саме щодо самих повідомлень змушує їх ніколи не бути більше 3000 символів? Якщо це просто довільне обмеження програми (скажімо, для текстового поля чи чогось іншого), використовуйте TEXTполе на рівні даних.


Що означає "що чудово, поки його немає"? Що означає "не"?
Pacerier

7
@Pacerier Щоб навести приклад "не" Джеймс, ймовірно, приблизно: Візьмемо для прикладу Twitter, який до недавнього часу мав обмеження на 140 символів на PM. Вони вирішили, що це більше не розумно, і вирішили повністю зняти цю межу. Якби вони не заздалегідь думали про це (що я майже впевнений, що вони, мабуть, зробили ...), вони би добігли до описаного вище сценарію.
PaulSkinner

9
Я просто розміщую нашу нову базу даних, і я припускав, що ніхто не міг би помістити більше 2000 символів у наші крихітні коробки для коментарів, а потім, як зазначає Джеймс, сьогодні вночі раптом "було не нормально", оскільки користувач перебрав дуже вагомий коментар, який був 2600 символів. Я використовував varchar (2000), думаючи, що це не може отримати довше, і я помилявся. так що так, це здорово, поки його немає. У нашому випадку на прояв знадобилося лише кілька днів. Правило нижче, Майкл Дж. Калкінс, я думаю, я буду користуватися відтепер. текст для повідомлень, коментарів.
Лізардкс

1
@Pacerier "який чудовий, поки не великий". Іншими словами, вона працює майже весь час і чудово ... за винятком тих виняткових ситуацій, коли вона не така велика.
Обмежене спокутування

@Pacerier В коментарях до вибраної відповіді згадується ще один цікавий приклад: в основному він мав обмеження в 2000 символів, але введені символи знаходилися на кодовій сторінці, яка насправді використовувала більше байтів, ніж звичайні літери, його база даних в кінцевому підсумку потребує місця для 24-символів лише тому, що йому довелося враховувати фактичний розмір байтів символів, що вводяться.
RaptorX

32

Відмова: Я не експерт MySQL ... але це моє розуміння проблем.

Я думаю, що TEXT зберігається поза рядком mysql, тоді як я думаю, що VARCHAR зберігається як частина рядка. Максимальна довжина рядків для рядків mysql .. тому ви можете обмежити кількість інших даних, які ви можете зберігати в рядку, використовуючи VARCHAR.

Зважаючи на те, що VARCHAR є частиною рядка, я підозрюю, що запити, що дивляться на це поле, будуть трохи швидшими, ніж запити, які використовують фрагмент TEXT.


38
Межа довжини рядка - 65 555 байт [ 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 5.5.
Pacerier

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, темпери варчару мають різну довжину.
Рік Джеймс

3

Існує велика різниця між VARCHAR і TEXT. Хоча поля VARCHAR можна індексувати, поля TEXT не можуть. Поля типу VARCHAR зберігаються вбудованим, тоді як TEXT зберігається в автономному режимі, лише вказівники на дані TEXT фактично зберігаються в записах.

Якщо вам доведеться проіндексувати своє поле для швидшого пошуку, оновлення чи видалення, ніж для VARCHAR, незалежно від величини. VARCHAR (10000000) ніколи не буде збігатися з полем TEXT, оскільки ці два типи даних відрізняються за своєю суттю.

  • Якщо ви використовуєте поле лише для архівації
  • вам не байдуже відновлення швидкості передачі даних
  • вам важлива швидкість, але ви будете використовувати оператор "LIKE%" у своєму пошуковому запиті, тому індексація не допоможе багато
  • не можна передбачити обмеження довжини даних

ніж їхати на TEXT.


Інформація про частково оманливу інформацію: стовпці TEXT не можуть бути індексованими у повному обсязі. Коли ви додаєте стовпець ТЕКСТ в індекс, ви повинні вказати довжину. Також VARCHAR не можна індексувати їх у повному обсязі у випадку VARCHARs> 255, оскільки на розмір індексу існує максимальна довжина.
eRadical

2

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

Продуктивність Varchar є більш потужною, оскільки вона працює повністю з пам'яті, але це не буде так, якщо дані занадто великі, varchar(4000)наприклад.

Текст, з іншого боку, не прилипає до пам'яті і впливає на продуктивність диска, але ви можете цього уникнути, розділивши текстові дані в окрему таблицю та застосувавши лівий запит приєднання, щоб отримати текстові дані.

Blob набагато повільніше, тому використовуйте його, лише якщо у вас немає таких даних, як 10000 зображень, які коштують 10000 записів.

Дотримуйтесь цих порад щодо максимальної швидкості та продуктивності:

  1. Використовуйте varchar для імені, назв, електронних листів

  2. Використовуйте текст для великих даних

  3. Відокремлений текст у різних таблицях

  4. Використовуйте запити зліва приєднатися до ідентифікатора, такого як номер телефону

  5. Якщо ви збираєтесь використовувати Blob, застосовуйте ті самі поради, що і в тексті

Це зробить запити в мілісекундах на таблицях з даними> 10 М та розміром до 10 ГБ.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.