Чи є недоліки використання загального варшара (255) для всіх текстових полів?


100

У мене є contactsтаблиця , яка містить такі поля, як postcode, first name, last name, town, country, і phone numberт.д., всі з яких визначені як VARCHAR(255)навіть якщо жоден з цих полів НЕ буде коли - небудь близько до того 255 символів. (Якщо вам цікаво, це так, тому що Ruby on Rails мігрує карту String поля VARCHAR(255)за замовчуванням, і я ніколи не намагався її замінити).

Оскільки VARCHAR буде зберігати лише кількість фактичних символів поля (разом із довжиною поля), чи є якась вигідна перевага (продуктивність чи інше) у використанні, скажімо, VARCHAR(16)над VARCHAR(255)?

Крім того, більшість із цих полів мають на них індекси. Чи впливає більший розмір VARCHAR на полі взагалі на розмір або продуктивність індексу?

FYI Я використовую MySQL 5.


2
@ceejayoz, заявивши, що прийнята відповідь невірна, не пояснюючи, чому насправді це не допомагає. Ще гірше - це те, що прийнята відповідь може змінюватися з часом, і ваш коментар заплутає людей у ​​думці, що нова прийнята відповідь є невірною.
Гілі

1
@Gili Видалив мій коментар, оскільки ОП, очевидно, змінило їхнє прийняття. Хороші моменти, в майбутньому я зазначу, про яку відповідь я говорю і чому.
ceejayoz

Ще кілька відповідей на це повторне запитання, stackoverflow.com/questions/1262174/…
Джеймс Макмахон

Відповіді:


129

У пам’яті VARCHAR(255)досить розумно зберігати лише потрібну вам довжину в заданому рядку, на відміну від CHAR(255)якого завжди зберігалося б 255 символів.

Але оскільки ви позначили це питання за допомогою MySQL, я згадаю підказку, що стосується MySQL: коли рядки копіюються з шару двигуна зберігання на рівень SQL, VARCHARполя перетворюються на те, CHARщоб отримати перевагу роботи з рядками з фіксованою шириною. Таким чином, рядки в пам'яті стають вичерпаними до максимальної довжини оголошеного VARCHARстовпця.

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

Можливо, вам також захочеться знати, що така поведінка "витіснення" означає, що рядок, оголошений набором символів utf8, виділяє три байти на символ навіть для рядків, які ви зберігаєте з однобайтовим вмістом (наприклад, символи ascii або latin1). І так само набір символів utf8mb4 призводить до того, що рядок має не більше чотирьох байтів на символ у пам'яті.

Таким чином, VARCHAR(255)у utf8, що зберігає короткий рядок типу "Без думки", на диску береться 11 байт (десять символів нижньої діаграми плюс один байт на довжину), але це займає 765 байт у пам'яті, а значить, у тимчасових таблицях або відсортованих результатах.

Я допомагав користувачам MySQL, які несвідомо створювали темп-таблиці 1,5 ГБ часто і заповнювали свій дисковий простір. У них було багато VARCHAR(255)колонок, які на практиці зберігали дуже короткі рядки.

Краще визначити стовпчик на основі типу даних, які ви збираєтесь зберігати. Це має переваги для застосування обмежень, пов’язаних із додатком, як згадували інші. Але це має фізичну користь, щоб уникнути втрати пам’яті, яку я описав вище.

Звичайно, важко дізнатися, що таке найдовша поштова адреса, саме тому багато людей вибирають довгу, VARCHARяка, звичайно, довша за будь-яку адресу. І 255 є звичайним, оскільки це максимальна довжина a, VARCHARдля якої довжина може бути закодована одним байтом. Це також була максимальна VARCHARдовжина в MySQL старше 5,0.


6
Я завжди думав, що 255використовується так, щоб довжина струни могла вписатися в один байт
BlueRaja - Danny Pflughoeft

3
@BlueRaja: Це, мабуть, було вірно для баз даних, внутрішня структура файлів яких кодувала довжину рядка в одному байті, або якщо вони кодували короткі рядки в одному байті. Але це не стосується більшості баз даних.
Білл Карвін

7
@BlueRaja: InnoDB не зберігає довжину наступного варшара, він зберігає ряд зрушень поля для всіх полів у рядку. Ці компенсації поля можуть бути 1 байт, якщо загальний розмір рядка менше 127 байт, або ще 2 байти. Дивіться forge.mysql.com/wiki/MySQL_Internals_InnoDB
Білл Карвін

6
@BlueRaja: MyISAM (для тих, хто все ще користується ним) зберігає варчарські довжини, і вони можуть зберігатися в 1 або 2 байтах. Однак: "Відсилаючи ключ обробнику для index_read () або records_in_range, ми завжди використовуємо 2-байтну довжину для VARCHAR, щоб зробити речі простішими." Дивіться forge.mysql.com/wiki/MySQL_Internals_MyISAM
Білл Карвін

1
одне питання - сортування та групування за будь-яким полем чи самим варчарським полем?
Рохіт Банга

24

На додаток до розміру та продуктивності щодо встановлення розміру варшара (і, можливо, важливішого, оскільки зберігання та обробка дешевшають щосекунди), недолік використання varchar (255) "лише тому, що" знижується цілісність даних .

Визначення максимальних обмежень для рядків - це добре робити, щоб запобігти введенню RDBMS довше, ніж очікувалося, і викликати перевищення буфера або винятки / помилки пізніше при отриманні та аналізі значень із бази даних, які довші (більше байтів), ніж очікувалося.

Наприклад, якщо у вас є поле, яке приймає рядки з двома символами для скорочень країн, тоді у вас немає можливих підстав очікувати, що ваші користувачі (в цьому контексті програмісти) введуть повні назви країн. Оскільки ви не хочете, щоб вони входили в "Антигуа і Барбуду" (AG) або "Острови Херда і Макдональд" (HM), ви не дозволяєте це на рівні бази даних. Крім того, певно, що деякі програмісти ще не RTFMed проектну документацію ( яка, безумовно, існує ) знати, що не робити цього.

Встановіть поле, щоб прийняти два символи, і дозвольте RDBMS впоратися з ним (витончено шляхом обрізання або недоброзичливо, відхиляючи їх SQL з помилкою).

Приклади реальних даних, які не мають підстави перевищувати певну довжину:

  • Канадські поштові індекси мають формат A1A1A1 і завжди мають 6 символів, навіть для Діда Мороза (6 символів виключає простір, який можна вказати для розбірливості).
  • адреси електронної пошти - до 64 байт до @, до 255 байт після. Ніколи більше, щоб не зламати Інтернет.
  • Північноамериканські телефонні номери ніколи не перевищують 10 цифр (за винятком коду країни).
  • На комп’ютерах, що працюють (останні версії) Windows не можуть бути назви комп'ютерів довше 63 байт , хоча більше 15 не рекомендується, і вони порушать ферму серверів Windows NT.
  • Скорочення штатів - 2 символи (наприклад, наведені вище коди країн)
  • Номери відстеження UPS мають довжину 18-, 12-, 11- або 9 символів. 18-символьні цифри починаються з "1Z", а 11-символьні цифри починаються з "T", що змушує задуматися, як вони доставляють усі ці пакунки, якщо вони не знають різниці між літерами та цифрами.

І так далі...

Знайдіть час, щоб подумати про свої дані та її межі. Якщо ви архітектор, розробник чи програміст, це ваша робота .

Використовуючи varchar (n) замість varchar (255), ви усунете проблему, коли користувачі (кінцеві користувачі, програмісти, інші програми) вводять несподівано довгі дані, які пізніше повертатимуться до переслідування вашого коду.

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


5
Канадські поштові індекси насправді мають 7 цифр, простір посередині важливий і має бути вказаний на поштових етикетках. Номери телефонів у північноамериканських країнах можуть містити більше 10 цифр, якщо вони мають місце. Якщо ви все в порядку, не можете зберігати розширення телефонних номерів, то 10 цифр добре, але ви, мабуть, пошкодуєте про це.
Кіббі

3
Однозначно є випадок обмеження цілісності даних. Хоча бути занадто обмежуючим все ж просто. Вводити обмеження для даних , контролю і накладати розсудливих обмеження для вимог до даними ви не можете контролювати. Обмеження вашого номера телефону та електронної пошти (якщо ви ніколи не інтернаціоналізуєтесь). Ваша вимога, яка говорить про те, що обрізання коду країни з двома символами є "витонченою" справою, є божевільним. Ви знаєте, що сталася помилка, не вкорочуйте і не приймайте. Якщо урізати, є надзвичайно велика ймовірність, що у вас виникне неправильний код країни.
coderjoe

Більшість додатків пройдуть перевірку даних, перш ніж надсилати їх у базу даних ...
Cobby

2
Звичайно. Більшість. Але я вважаю, що тут ви припускаєте, що розробник, який розробляє нову програму для існуючої бази даних, знає про обмеження щодо даних (ми не всі експерти по кожному типу даних і як вони реалізуються у кожній базі даних ). Тільки тому, що ви можете перевірити дані у своїй програмі, це не означає, що ви зробили це.
shufler

3
the design documentation (which surely exists)Ха-ха. : D
Каміло Мартін

14

Я з тобою. Метушлива увага до деталей - це біль у шиї і має обмежене значення.

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

Якщо ви використовуєте лише поля CHAR, ви можете отримати рядки фіксованої довжини. Це може зберегти деякий дисковий режим перезавантаження, якщо ви вибрали точні розміри для полів. Ви можете отримати більш щільно упаковані дані (менше вводу-виводу для сканування таблиць) і більш швидкі оновлення (простіше знайти відкриті пробіли в блоці для оновлень і вставок.)

Однак, якщо ви завищуєте свої розміри або фактичні розміри даних варіюються, ви витрачаєте витрачені місця на поля CHAR. Дані з'являться менш щільно упакованими (що призводить до більшої кількості вводу-виводу для великих пошукових запитів).

Як правило, переваги продуктивності від спроби навести розмір на змінні поля незначні. Ви можете легко порівняти, використовуючи VARCHAR (255) порівняно з CHAR (x), щоб побачити, чи можете ви виміряти різницю.

Однак іноді мені потрібно надати підказку "малий", "середній", "великий". Тому я використовую 16, 64 та 255 для розмірів.


13

Сьогодні я не можу уявити, що це вже справді важливо.

Існує обчислювальна витрата на використання полів змінної довжини, але з надлишком процесорів сьогодні, це навіть не варто думати. Система вводу / виводу настільки повільна, що дозволяє зробити будь-які обчислювальні витрати для ефективного поводження з варшарами. Насправді, ціна варчара обчислювально, ймовірно, є чистою виграшем над кількістю дискового простору, заощадженим за допомогою полів змінної довжини над полями фіксованої довжини. Ви, швидше за все, маєте більшу щільність рядків.

Тепер, складність полів varchar полягає в тому, що ви не можете легко знайти запис через свій рекордний номер. Якщо у вас розмір рядка з фіксованою довжиною (із полями фіксованої довжини), тривіально обчислити блок диска, на який вказує ідентифікатор рядка. Із змінною довжиною рядка такий вид виходить у вікно.

Отже, тепер вам потрібно підтримувати якийсь індекс числа записів, як і будь-який інший первинний ключ, АБО вам потрібно зробити надійний ідентифікатор рядка, який кодує деталі (наприклад, блок тощо) в ідентифікатор. Якщо ви це зробите, ідентифікатор повинен буде перераховуватися, якщо коли-небудь рядок буде переміщено на постійне сховище. Не важливо, просто потрібно переписати всі записи індексу і переконайтесь, що ви або: а) ніколи не виставляйте його споживачеві, або б) ніколи не стверджуйте, що номер надійний.

Але оскільки у нас є поля varchar сьогодні, єдине значення varchar (16) над varchar (255) полягає в тому, що БД буде застосовувати обмеження 16 char на varchar (16). Якщо модель БД повинна бути фактично репрезентативною для фізичної моделі даних, то наявність довжин полів може мати значення. Якщо, однак, це просто "сховище", а не "модель І сховище", нічого в цьому немає.

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


5

На мій досвід, якщо ви дозволите тип даних на 255 символів, якийсь дурний користувач (або досвідчений тестер) насправді заповнить це.

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

Набагато простіше вибрати розумний ліміт на початку, а потім застосувати це через додаток та базу даних.


0

Добра практика виділити лише трохи того, що вам потрібно. Номери телефонів ніколи не будуть настільки великими.

Однією з причин є те, що якщо ви не підтвердите велику кількість записів, без сумніву, хтось використає все, що є. Тоді у вашому ряду може не вистачити місця. Я не впевнений у обмеженні MySQL, але 8060 - це максимальний розмір рядків у MS SQL.

Більш нормальним за замовчуванням буде 50 imho, а потім збільшити там, де це доведе.


Дякую. Я безумовно погоджуюсь, що це хороша практика. Це дуже важливий аспект виступу
Olly

0

У контексті mysql це може отримати важливе значення при роботі з індексами на зазначених колонках varchar, оскільки mysql має макс. ліміт 767 байт на індексний рядок

Це означає, що при додаванні індексу через декілька стовпців varchar 255 ви можете досить швидко / навіть швидше дійти до цієї межі у стовпцях utf8 або utf8mb4, як зазначено у відповідях вище

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