MySQL - варчарська довжина та продуктивність


Відповіді:


31

Це дуже поширене "питання на іспит / співбесіду". Я відповім як можна краще:

У стандартних форматах рядків для InnoDB та MyISAM (динамічний / компактний) a VARCHAR(50)та a VARCHAR(255)зберігатимуть текст рядка таким же чином - 1 байт на довжину та фактичний рядок від 1 до 4 байт на символ (залежно від кодування та фактичний символ зберігається).

Насправді, якщо я добре пам’ятаю, я згадую, що хтось модифікував словник даних з шістнадцятковим редактором, щоб змінити щось на зразок a VARCHAR(50)на a VARCHAR(100), щоб це могло бути зроблено динамічно (як правило, це потребує реконструкції таблиці). І це було можливо, оскільки фактичні дані не вплинули на цю зміну.

Це не вірно VARCHAR(256), тому що тоді завжди потрібно 2 байти (принаймні) для довжини.

Отже, це означає, що ми завжди повинні робити VARCHAR(255), чи не так? Ні. Є кілька причин.

Хоча InnoDB може зберігати варчар динамічно, це не стосується інших двигунів. MyISAM має фіксований формат розміру рядків, і таблиці 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 байти:

mysql> SELECT LENGTH(REPEAT('ñ', 255));
+---------------------------+
| LENGTH(REPEAT('ñ', 255))  |
+---------------------------+
|                       510 |
+---------------------------+
1 row in set (0.02 sec)

mysql> SELECT CHAR_LENGTH(REPEAT('ñ', 255));
+--------------------------------+
| CHAR_LENGTH(REPEAT('ñ', 255))  |
+--------------------------------+
|                            255 |
+--------------------------------+
1 row in set (0.00 sec)

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

Оновлення: Оскільки зростаюча популярність струн змінної довжини, наприклад, за допомогою емоджи, Oracle домагається підвищення продуктивності для цих випадків. В останніх версіях MySQL (5.6, 5.7) InnoDB був встановлений як двигун за замовчуванням як для внутрішніх, так і явних тимчасових таблиць, тобто поля змінної довжини тепер є першокласними громадянами. Це означає, що може бути менше причин мати дуже обмежену довжину символів (але вони все ще існують).

(*) Друге оновлення : великий_prefix_index тепер увімкнено за замовчуванням на останніх версіях MySQL (8.0), але це все ще справедливо для старих версій або якщо ви використовуєте старі формати файлів / рядків innodb (крім динамічного чи стисненого), але тепер за замовчуванням індекси одного стовпця можуть бути до 3072 байтів.


невелике оновлення: MySQL-8.0.13 + використовує TempTable за замовчуванням для темп-таблиць, які мають ефективне сховище для вархарів.
danblack

0

Забудьте про префікс 1- проти 2-байт на VARCHARs.

  • Це впливає на ефективність на незначну суму.
  • Це "2" частіше, ніж говорить очевидне правило.

На питання про 255 вже багато разів задавали і відповідали.

  • Занадто багато часу VARCHARsможе призвести до збою CREATE TABLE.
  • Тимчасові таблиці можуть перетворюватися на MEMORYтаблиці, з VARCHARsперетвореними на VARCHAR. Це означає, наприклад, що VARCHAR(255) CHARACTER SET utf8mb4потрібно фіксовану довжину 1020 байт. (Це не вдасться, і це перетвориться на використання MyISAM.)

Підсумок: не використовуйте сліпо 255 (або 256); робити те, що має сенс для схеми.

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