# 1071 - вказаний ключ був занадто довгим; Максимальна довжина ключа - 767 байт


562

Коли я виконав таку команду:

ALTER TABLE `mytable` ADD UNIQUE (
`column1` ,
`column2`
);

Я отримав це повідомлення про помилку:

#1071 - Specified key was too long; max key length is 767 bytes

Інформація про колонку1 та стовпчик2:

column1 varchar(20) utf8_general_ci
column2  varchar(500) utf8_general_ci

Я думаю, що varchar(20)потрібно лише 21 байт, тоді varchar(500)як потрібно лише 501 байт. Отже, загальна кількість байтів - 522, менше 767. То чому я отримав повідомлення про помилку?

#1071 - Specified key was too long; max key length is 767 bytes

5
Оскільки це не 520 байт, а, скоріше, 2080 байт, що набагато перевищує 767 байт, ви можете зробити колонку1 varchar (20) та column2 varchar (170). якщо ви хочете, щоб символ / байт був
рівним

3
Я думаю, що ваш розрахунок тут трохи неправильний. mysql використовує 1 або 2 додаткові байти для запису значень довжини: 1 байт, якщо максимальна довжина стовпця становить 255 байт або менше, 2, якщо вона довша за 255 байт. Для кодування utf8_general_ci потрібно 3 байти на символ, тому varchar (20) використовує 61 байт, varchar (500) використовує 1502 байти загалом 1563 байти
lackovic10

3
mysql> виберіть maxlen, character_set_name з information_schema.character_sets, де символ_set_name в ('latin1', 'utf8', 'utf8mb4'); макслен | символ_набору_– ------ | ------------------- 1 | латинська1 ------ | ------------------- 3 | utf8 ------ | ------------------- 4 | utf8mb4
lackovic10

15
'якщо ви хочете, щоб символ / байт був рівним, використовуйте latin1' Будь ласка , не робіть цього . Latin1 дійсно, дуже гарно. Ви пошкодуєте про це.
Штійн де Віт

Для вирішення зверніться до stackoverflow.com/a/52778785/2137210
Pratik

Відповіді:


490

767 байт - заявлене обмеження префікса для таблиць InnoDB у версії 5.6 MySQL (та попередніх версіях). Це 1000 байтів для таблиць MyISAM. У MySQL версії 5.7 і вище цей ліміт був збільшений до 3072 байт.

Ви також повинні мати на увазі, що якщо ви встановите індекс на велике поле char або varchar, яке закодовано utf8mb4, вам слід розділити максимальну довжину префікса індексу 767 байт (або 3072 байта) на 4, що призводить до 191. Це тому, що максимальна довжина символу utf8mb4 - чотири байти. Для символу utf8 це буде три байти, що призводить до максимальної довжини префікса - 254.

Один із варіантів - просто встановити нижню межу на полях VARCHAR.

Інший варіант (відповідно до відповіді на це питання ) - отримати підмножину стовпця, а не всю суму, тобто:

ALTER TABLE `mytable` ADD UNIQUE ( column1(15), column2(200) );

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


4
Застосувати, вказавши підмножину стовпця, а не всю суму. Гарне рішення.
Стівен

204
Це не пояснює, чому поля значно нижче межі довжини перевищують межу довжини ...
Серін

6
Я спробував редагувати інформацію @Cerin, яка відсутня вище, яка, очевидно, вважається відсутньою і іншими, але вона відхиляється як більш придатна як коментар. Для тих, хто намагається зрозуміти, чому 500 + 20> 767 дивіться коментар Стефана Ендрулліса щодо відповіді Жюльєна.
Летаріон

8
Це може бути проблемою. Наприклад: я маю ім'я поля (255) і додаю унікальне до цього поля під ім'ям (191), оскільки я використовую utf8mb4. Якщо у мене є користувач додати своє ім'я з «IJUE3ump5fiUuCi16jSofYS234MLschW4wsIktKiBrTPOTKBK6Vteh5pNuz1tKjy ... aO500mlJs» І інший користувач додати своє ім'я з цим «IJUE3ump5fiUuCi16jSofYS234MLschW4wsIktKiBrTPOTKBK6Vteh5pNuz1tKjy ... aO500mlJa» Різним є останнім символом. Він повинен пройти перевірку, яка не застрягла при повторному введенні.
vee

28
Межа індексу - 767 байт , а не символів. А оскільки utf8mb4набір символів Mysql (який решта світу називає utf8) потребує (щонайбільше) 4 байт на персонаж, ви можете індексувати лише до VARCHAR(191). utf8Набір символів Mysql (який решта світу називає зламаним) потребує не більше 3-х байт на символ, тому якщо ви використовуєте це (чого не слід ), ви можете проіндексувати доVARCHAR(255)
Stijn de Witt

403

Якщо у когось є проблеми з INNODB / Utf-8, намагаючись поставити UNIQUEіндекс на VARCHAR(256)поле, переключіть його на VARCHAR(255). Здається, 255 є обмеженням.


246
Кількість дозволених символів просто залежить від вашого набору символів. UTF8 може використовувати до 3 байт на символ, utf8mb4 - до 4 байт, а latin1 - лише 1 байт. Таким чином, для utf8 ваша довжина ключа обмежена 255 символами, оскільки 3*255 = 765 < 767.
Стефан Ендрулліс

9
Це врятувало мені багато розчарувань - дякую. Це має бути прийнятою відповіддю IMO, враховуючи, що користувач використовує InnoDB, стверджуючи, що вони потрапили в обмеження 767b.
TheCarver

8
Як заявив Штефан Ендрулліс, це залежить від діаграми. Якщо ви використовуєте UTF8, який використовує 3 байти: 255x3 = 765, що нижче межі 767, а 256x3 = 768, що вище. Але якщо ви використовуєте UTF8mb4, його 255 * 4 = 1020, то це не справжнє рішення
bernhardh

25
Ця відповідь правильна. Однак якщо 255 справді працює для вас, це означає, що ви використовуєте Mysql utf8, який, на жаль, порушений. Він може кодувати лише символи в основній багатомовній площині. У вас з’являться проблеми з персонажами, які випадають поза цим. Наприклад, ті персонажі Emoji, які вони додають, я думаю, що вони не впадають у нього. Тож замість того, щоб перейти на VARCHAR(255), переключіться на VARCHAR(191) та переключіть кодування на utf8mb4(що насправді просто utf8, але MySql хотів утримати назад. Compat).
Штійн де Вітт

1
Не корисно для мого багатоколінного унікального обмеження. Це також не спрацювало б для багатокольорового унікального обмеження ОП. (дав би йому загальний розмір 825 байт)
Баретт

351

Коли ви досягнете межі. Встановіть наступне.

  • ІННОДБ utf8 VARCHAR(255)
  • ІННОДБ utf8mb4 VARCHAR(191)

34
Це найкраща відповідь. Простий, прямо до точки, а також включає utf8mb4ліміт (який є найбільш використовуваним кодуванням для нових баз даних, оскільки він приймає емоджи / etc).
Клаудіо Голландія

10
тому що 767/4 ~ = 191, а 767/3 ~ = 255
бухгалтер від

11
де і як його встановити?
Дінеш Сонячний

1
Так, вказавши ENGINE=InnoDB DEFAULT CHARSET=utf8в кінці CREATE TABLEтвердження, що я міг мати VARCHAR(255)первинний ключ. Дякую.
xonya

1
хтось дасть йому +1, щоб перевищити ліміт 191 :)
cagcak

147

MySQL передбачає найгірший випадок для кількості байтів на символ у рядку. Для кодування "utf8" MySQL це 3 байти на символ, оскільки таке кодування не дозволяє використовувати символи U+FFFF. Для кодування MySQL 'utf8mb4' це 4 байти на символ, оскільки саме так MySQL називає фактичний UTF-8.

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


4
- Що імовірно означає, що при використанні utf8mb4 мені потрібно встановити їх (щонайбільше) 191 як 191 * 4 = 764 <767.
Ісаак

2
@Isaac Так, саме,
morganwahl

2
Я думаю, це може бути правильною відповіддю, але ви могли б детальніше розглянути, що потрібно зробити, щоб виправити таке питання? Принаймні для нобіїв MySQL, як я?
Адам Грант

Немає жодного способу обійти цю межу індексу. Тут йдеться про унікальні обмеження; для них ви можете мати один стовпчик тексту необмеженої довжини, а інший, де ви зберігаєте хеш (як MD5) цього тексту, і використовувати хеш-стовпець для свого унікального обмеження. Вам потрібно буде забезпечити, щоб ваша програма постійно оновлювала хеші, коли вона змінює текст, але існують різні способи впоратися з цим без особливих проблем. Відверто кажучи, MySQL повинен реалізувати таку річ сам, щоб вам не довелося; Я не здивуюсь, якщо MariaDB має щось подібне.
morganwahl

Унікальний індекс на дуже довгій колонці вархара зустрічається рідко. Подумайте, навіщо це вам потрібно, оскільки це може бути проблемою дизайну. Якщо ви просто хочете вказувати на ньому індекс для пошуку, розгляньте поле "ключових слів", яке вміщується в межах 191 символу, або розділити текст на короткий опис і довгий / повний текст тощо. Або якщо вам дійсно потрібен повнотекстовий пошук, подумайте про використання спеціалізованого програмного забезпечення для це, наприклад, Apache Lucene.
Штійн де Вітт

56

запустіть цей запит перед запитом:

SET @@global.innodb_large_prefix = 1;

це збільшить межу до 3072 bytes.


4
Чи є якийсь мінус у зміні на innodb_large_prefix в усьому світі? І це БД "глобальна" чи всі БД ВСІМО ГЛОБАЛЬНИМ?
SciPhi

5
Застосовується лише при використанні нестандартних форматів рядків. Див dev.mysql.com/doc/refman/5.5/en / ... . Зокрема, "Увімкніть цю опцію, щоб дозволити префікси ключових індексів більше 767 байт (до 3072 байт) для таблиць InnoDB, які використовують формати рядків DYNAMIC і COMPRESSED." Формат рядків за замовчуванням не впливає.
Кріс Лір

5
Це добре працювало для мене - більше деталей і керівництво можна знайти тут: mechanics.flite.com/blog/2014/07/29 / ...
ВУХО

1
нам потрібно перезапустити mysql-сервер після цього?
SimpleGuy

7
Важливі пропущені деталі цієї відповіді. innodb_file_formatповинно бути BARRACUDAта На рівні таблиці ви повинні використовувати ROW_FORMAT=DYNAMICабо ROW_FORMAT=COMPRESSED. Дивіться коментар @ cwd вище з посібником.
q0rban

46

Рішення для Laravel Framework

Відповідно до документації Laravel 5.4. * ; Ви повинні встановити довжину рядка за замовчуванням у bootметоді app/Providers/AppServiceProvider.phpфайлу наступним чином:

use Illuminate\Support\Facades\Schema;

public function boot() 
{
    Schema::defaultStringLength(191); 
}

Пояснення цього виправлення, надане Laravel 5.4. * Документацією :

Laravel використовує utf8mb4набір символів за замовчуванням, який включає підтримку зберігання "емоджи" в базі даних. Якщо ви використовуєте версію MySQL, старшу за версію 5.7.7 або MariaDB, старшу за версію 10.2.2, можливо, вам доведеться вручну налаштувати довжину рядка за замовчуванням, згенеровану міграціями, щоб MySQL створив для них індекси. Ви можете налаштувати це, зателефонувавши Schema::defaultStringLengthу ваш метод AppServiceProvider.

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


10
@BojanPetkovic добре, що я щойно прийшов із питання про Laravel, і ця відповідь фактично вирішила мою проблему.
mkmnstr

Ця відповідь чудова. Але хтось знає, чому саме це працює?
UeliDeSchwert

1
Документація @Bobby Laravel дає своє пояснення в рубриці "Індекс довжини та MySQL / MariaDB" laravel.com/docs/5.4/migrations#creating-indexes
Алі Шаукат

1
@Bobby Я оновив відповідь. Я додав пояснення, надані документацією laravel для цього виправлення.
Алі Шаукат

39

Яке кодування символів ви використовуєте? У деяких наборах символів (наприклад, UTF-16 та ін.) Використовується більше одного байта на символ.


8
Якщо це UTF8, символ може використовувати до 4-х байт, так що 20-символьний стовпець є 20 * 4 + 1байтами, а стовпець 500 знаків - 500 * 4 + 2байтами
Thanatos

5
Що для цього варто, у мене просто була та сама проблема, і перехід з utf8_general_ci на utf8_unicode_ci вирішив проблему для мене. Не знаю, чому хоч :(
Andresch Serj

11
Для VARCHAR(256)стовпця з UNIQUEіндексом зміна зіставлення не мала для мене ефекту, як це було зроблено для @Andresch. Однак скорочення довжини з 256 до 255 все ж вирішило це. Я не розумію, чому 767 / макс 4 байти на символ дають максимум 191?
Ар'ян

10
255*3 = 765; 256*3 = 768. Здається, ваш сервер припускав 3 байти на символ, @Arjan
Amber

21
@Greg: Ви маєте рацію, але це слід уточнити: сам UTF-8 використовує 1–4 байти на кодову точку. У "наборах символів" MySQL (дійсно кодування) є набір символів під назвою "utf8", який здатний кодувати частину UTF-8 і використовує 1–3 байти в кодовій точці, і не здатний кодувати точки коду за межами BMP. Він також включає ще один набір символів під назвою "utf8mb4", який використовує 1-4 байти на кодову точку і здатний кодувати всі точки коду Unicode. (utf8mb4 - UTF-8, utf8 - дивна версія UTF-8.)
Танатос

28

Я думаю, що для varchar (20) потрібно лише 21 байт, тоді як varchar (500) вимагає лише 501 байт. Отже, загальна кількість байтів - 522, менше 767. То чому я отримав повідомлення про помилку?

Для зберігання рядка UTF8 потрібно 3 байти на символ , тому у вашому випадку 20 + 500 символів = 20 * 3 + 500 * 3 = 1560 байт, що більше, ніж дозволено 767 байт.

Обмеження для UTF8 становить 767/3 = 255 символів , для UTF8mb4, який використовує 4 байти на символ, це 767/4 = 191 символ.


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

  1. Використовуйте "дешевше" кодування (те, що вимагає менше байтів на персонаж)
    У моєму випадку мені потрібно було додати унікальний індекс на стовпчик, що містить SEO рядок статті, оскільки я використовую лише [A-z0-9\-]символи для SEO, я використовував, latin1_general_ciякий використовує лише один байт на символ і тому стовпець може мати довжину 767 байт.
  2. Створіть хеш із стовпця та використовуйте унікальний індекс лише для цього
    . Іншим варіантом для мене було створення ще одного стовпця, який би зберігав хеш SEO, цей стовпець мав би UNIQUEключ до того, щоб значення SEO були унікальними. Я також додав би KEYіндекс до оригінальної колонки SEO, щоб пришвидшити пошук.

Це зробило трюк. У мене був varchar (256), і мені довелося змінити його на varchar (250).
MaRmAR

25

Тут вже відповіли багато користувачів про те, чому ви отримуєте повідомлення про помилку. Моя відповідь - про те, як це виправити та використовувати як є.

Перейдіть за цим посиланням .

  1. Відкрийте клієнт MySQL (або клієнт MariaDB). Це інструмент командного рядка.
  2. Він запитає ваш пароль, вводить ваш правильний пароль.
  3. Виберіть вашу базу даних за допомогою цієї команди use my_database_name;

База даних змінена

  1. set global innodb_large_prefix=on;

Запит OK, 0 рядків задіяно (0,00 сек)

  1. set global innodb_file_format=Barracuda;

Запит добре, 0 рядків зачеплені (0,02 сек)

  1. Перейдіть у свою базу даних на phpMyAdmin або щось подібне для зручного управління. > Виберіть базу даних> Перегляд структури таблиці > Перейдіть на вкладку « Операції ». > Змініть ROW_FORMAT на DYNAMIC і збережіть зміни.
  2. Перейдіть на вкладку структури таблиці> Натисніть кнопку Унікальна .
  3. Зроблено. Тепер у нього не повинно бути помилок.

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


якщо ви все-таки помиляєтесь після введення вищевказаного запиту, спробуйте перейти до "phpmyadmin"> встановіть "зіставлення" за вашими уподобаннями (для мене я використовую "utf8_general_ci")> натисніть кнопку застосувати (навіть якщо його вже utf8)
Ентоні Кал,

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

20
Specified key was too long; max key length is 767 bytes

Ви отримали це повідомлення, оскільки 1 байт дорівнює 1 символу, лише якщо ви використовуєте latin-1набір символів. Якщо ви використовуєте utf8, кожен символ вважатиметься 3 байтами при визначенні ключового стовпця. Якщо ви користуєтесь utf8mb4, кожен символ вважатиметься 4 байтами при визначенні вашого стовпця ключа. Таким чином, вам потрібно помножити ліміт символів вашого ключового поля на, 1, 3 або 4 (на моєму прикладі), щоб визначити кількість байтів, яке намагається дозволити поле ключа. Якщо ви використовуєте uft8mb4, ви можете визначити лише 191 символ для рідного, InnoDB, поля первинного ключа. Просто не порушуйте 767 байт.


16

ви можете додати стовпчик md5 довгих стовпців


Зауважте, що це не дозволить зробити сканування діапазону над цими стовпцями. Довжина префіксу на VARCHAR дозволить вам зберегти цю ознаку, викликаючи при цьому можливі помилкові збіги в індексі (і сканування та пошук рядків для їх усунення) (див. Прийняту відповідь). (Це, по суті, реалізований хеш-індекс вручну, який, на жаль, MysQL не підтримує з таблицями InnoDB.)
Thanatos

Я не міг використовувати індекси префікса, оскільки мені потрібно було підтримувати сумісність з H2 для тестування, і я виявив, що за допомогою хеш-колонки добре працює. я б настійно рекомендую використовувати функцію, стійку до зіткнення, таку як SHA1 замість MD5, щоб запобігти зловмисникам не створювати зіткнень. Збій індексу може бути використаний для витоку даних, якщо один із ваших запитів перевіряє лише хеш-значення, а не повне значення стовпця.
Маленький Майк

16

Замінити utf8mb4з utf8в файлі імпорту.

введіть тут опис зображення


Чому саме слід це робити? Крім того, якщо це має якісь недоліки (які я припускаю), вам слід згадати про це
Ніко Хааз,

13

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

Під час використання utf8mb4 символи розраховуються як 4 байти, тоді як під utf8 вони можуть бути 3 байтами. Бази даних InnoDB мають обмеження, що індекси можуть містити лише 767 байт. Отже, використовуючи utf8, ви можете зберігати 255 символів (767/3 = 255), але використовуючи utf8mb4, ви можете зберігати лише 191 символ (767/4 = 191).

Ви абсолютно можете додати звичайні індекси для VARCHAR(255)полів, використовуючи utf8mb4, але те, що відбувається - розмір індексу скорочується на 191 символ автоматично - як unique_keyтут:

Скріншот Sequel Pro, що показує урізаний індекс на 191 символ

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

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

Зрештою, якщо ви хочете мати унікальний індекс на полі, весь вміст поля повинен вміщуватися в індекс. Для utf8mb4 це означає зменшити довжину поля VARCHAR до 191 символу або менше. Якщо вам не потрібна utf8mb4 для цієї таблиці або поля, ви можете повернути її до utf8 і мати змогу зберегти свої поля довжиною 255.


11

Ось моя оригінальна відповідь:

Я просто скидаю базу даних і відтворюю так, і помилка відсутня:

drop database if exists rhodes; create database rhodes default CHARACTER set utf8 default COLLATE utf8_general_ci;

Однак це працює не у всіх випадках.

Це фактично проблема використання індексів на стовпцях VARCHAR з набором символів utf8(або utf8mb4), з стовпцями VARCHAR, що мають більше певної довжини символів. У випадку utf8mb4, що певна довжина дорівнює 191.

Для отримання додаткової інформації про використання довгих індексів у базі даних MySQL див. набір символів-utf8mb4


Вирішено проблему з налаштуванням відкритих засідань (до речі, ви врятували мою ніч :-)
Людо,

11

5 обхідних шляхів:

Ліміт був підвищений у 5.7.7 (MariaDB 10.2.2?). І її можна збільшити за допомогою деякої роботи в 5.6 (10.1).

Якщо ви досягаєте межі через спробу використання CHARACTER SET utf8mb4. Потім виконайте одне з наступних (у кожного є недолік), щоб уникнути помилки:

  Upgrade to 5.7.7 for 3072 byte limit -- your cloud may not provide this;
  Change 255 to 191 on the VARCHAR -- you lose any values longer than 191 characters (unlikely?);
  ALTER .. CONVERT TO utf8 -- you lose Emoji and some of Chinese;
  Use a "prefix" index -- you lose some of the performance benefits.
  Or... Stay with older version but perform 4 steps to raise the limit to 3072 bytes:

SET GLOBAL innodb_file_format=Barracuda;
SET GLOBAL innodb_file_per_table=1;
SET GLOBAL innodb_large_prefix=1;
logout & login (to get the global values);
ALTER TABLE tbl ROW_FORMAT=DYNAMIC;  -- (or COMPRESSED)

- http://mysql.rjweb.org/doc.php/limits#767_limit_in_innodb_indexes


10

Я вирішив цю проблему за допомогою:

varchar(200) 

замінено на

varchar(191)

усі варшари, яких налічується понад 200, замінюють їх на 191 або встановлюють текст.


Це те, що працювало і для мене. У мене був варчар (250), але дані ніколи не були такими довгими. Змінив його на варчар (100). Дякую за ідею :)
Арун Василь Лал

7

Я здійснив деякий пошук на цю тему, нарешті, отримав певні зміни

Для робочої версії MySQL 6.3.7 Версія доступна графічна міжфазова фаза

  1. Запустіть Workbench та виберіть з'єднання.
  2. Перейдіть до управління чи екземпляра та виберіть Файл опцій.
  3. Якщо Workbench попросить вас дозволити прочитати файл конфігурації, а потім дозвольте його, натиснувши ОК два рази.
  4. На центральне місце приходить вікно файлу параметрів адміністратора.
  5. Перейдіть на вкладку InnoDB і перевірте innodb_large_prefix, якщо він не встановлений у розділі Загальні.
  6. встановіть для параметра innodb_default_row_format значення DYNAMIC.

Для версій нижче 6.3.7 прямі опції недоступні, тому потрібно перейти до командного рядка

  1. Запустіть CMD як адміністратор.
  2. Перейдіть до директора, де встановлено сервер mysql Більшість випадків - це в "C: \ Program Files \ MySQL \ MySQL Server 5.7 \ bin", тому команда - "cd \" "CD Програмні файли \ MySQL \ MySQL Server 5.7 \ bin".
  3. Тепер запустіть команду mysql -u userName -p databasescheema Тепер вона запитала пароль відповідного користувача. Введіть пароль і введіть у запит mysql.
  4. Ми повинні встановити деякі глобальні налаштування, введіть команди нижче, одна за одною, глобальний innodb_large_prefix = увімкнено; встановити глобальний innodb_file_format = barracuda; встановити глобальний innodb_file_per_table = true;
  5. Тепер, нарешті, ми повинні змінити ROW_FORMAT необхідної таблиці за замовчуванням її COMPACT, ми повинні встановити її на DYNAMIC.
  6. використовувати наступну команду alter table table_name ROW_FORMAT = DYNAMIC;
  7. Зроблено

Я не можу цього знайти: 6. встановіть для параметра параметр innodb_default_row_format значення DYNAMIC.
Адріан Сид Альмагюр

якщо я використовую, set global innodb_default_row_format = DYNAMIC;я бачу це повідомлення: ПОМИЛКА 1193 (HY000): Невідома системна змінна 'innodb_default_row_format'
Адріан Cid Almaguer

як ви помилилися від workbench до cmd? Я це зробив із верстака, у нього є варіант безпосередньо.
Абхішек

Я роблю це з CMD, тому що не бачу цього варіанту у Workbench
Adrian Cid Almaguer

1
Я бачу проблему, що цей var був введений у v5.7.9, і у мене версія v5.6.33, спасибі
Адріан Сид Альмагуер

7

Для laravel 5,7 до 6,0

Кроки, які слід виконати

  1. Йти до App\Providers\AppServiceProvider.php .
  2. Додайте це до постачальника use Illuminate\Support\Facades\Schema; вгорі.
  3. Всередині функції завантаження Додайте це Schema::defaultStringLength(191);

що все, насолоджуйтесь.


Працював і для Laravel 5.8.
Нео

Це погане рішення. Причина: індекси не повинні бути нескінченно-довгими. Коли ви застосовуєте унікальний індекс до чогось, ви хочете, щоб індекс був фіксованим - більшу частину часу. Це означає, що НЕ ТРЕБИТИ робити такі речі, як emailунікальні, але вам слід хеш-лист і зробити його унікальним. На відміну від необроблених рядкових даних, хеші мають фіксовану ширину і їх можна індексувати та робити унікальними без проблем. Замість того, щоб зрозуміти проблему, ви поширюєте жахливі практики, які не мають масштабів.
NB

5

змінити своє порівняння. Ви можете використовувати utf8_general_ci, який підтримує майже всіх


"Майже" - досить хороший натяк, що це не довгострокове рішення
Ніко Хааз

4

Тільки зміни utf8mb4в utf8при створенні таблиць вирішити мою проблему. Наприклад: CREATE TABLE ... DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;до CREATE TABLE ... DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;.


4

Щоб виправити це, це працює для мене як шарм.

ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;

Я підтверджую, що моєю проблемою було також порівняння бази даних. У мене немає пояснень для цього. Я використовую mysql v5.6.32, а зіставлення БД було utf8mb4_unicode_ci.
махіард

2

Спираючись на поданий нижче стовпчик, ці 2 стовпчики змінних рядків використовують utf8_general_ciзіставлення ( utf8діаграма мається на увазі).

У MySQL utf8charset використовує максимум 3 байти для кожного символу. Таким чином, потрібно було б виділити 500 * 3 = 1500 байт, що набагато більше, ніж дозволяє 767 байт, який дозволяє MySQL. Ось чому ви отримуєте цю помилку 1071.

Іншими словами, вам потрібно обчислити кількість символів , заснований на поданні байт кодову сторінку як не кожен набір символів один байт уявлення (як передбачається) . IE utf8в MySQL є використання в більшості 3 байта на символ, 767 / 3≈255 символів, і дляutf8mb4 , максимум, 4-байтне представлення, 767 / 4≈191 символ.

Також відомо, що MySQL

column1 varchar(20) utf8_general_ci
column2  varchar(500) utf8_general_ci

1

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

SELECT
  c.TABLE_NAME As TableName,
  c.COLUMN_NAME AS ColumnName,
  c.DATA_TYPE AS DataType,
  c.CHARACTER_MAXIMUM_LENGTH AS ColumnLength,
  s.INDEX_NAME AS IndexName
FROM information_schema.COLUMNS AS c
INNER JOIN information_schema.statistics AS s
  ON s.table_name = c.TABLE_NAME
 AND s.COLUMN_NAME = c.COLUMN_NAME 
WHERE c.TABLE_SCHEMA = DATABASE()
  AND c.CHARACTER_MAXIMUM_LENGTH > 191 
  AND c.DATA_TYPE IN ('char', 'varchar', 'text')

1

Перевірте, чи sql_modeподобається

sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

якщо є, перейдіть на

sql_mode=NO_ENGINE_SUBSTITUTION

АБО

перезапустіть сервер, змінивши файл my.cnf (поставивши наступне)

innodb_large_prefix=on

1

У моєму випадку у мене виникла ця проблема, коли я створював резервну копію бази даних за допомогою символів виводу / вводу перенаправлення Linux. Тому я змінюю синтаксис, як описано нижче. PS: використання linux або mac-терміналу.

Резервне копіювання (без перенаправлення)

# mysqldump -u root -p databasename -r bkp.sql

Відновити (без <переспрямування)

# mysql -u root -p --default-character-set=utf8 databasename
mysql> SET names 'utf8'
mysql> SOURCE bkp.sql

Помилка "Вказаний ключ був занадто довгим; максимальна довжина ключа - 767 байт", просто зникла.


1

Індекс довжини та MySQL / MariaDB


Laravel використовує набір символів utf8mb4 за замовчуванням, який включає підтримку зберігання "емоджи" в базі даних. Якщо ви використовуєте версію MySQL, старшу за версію 5.7.7 або MariaDB, старшу за версію 10.2.2, можливо, вам доведеться вручну налаштувати довжину рядка за замовчуванням, згенеровану міграціями, щоб MySQL створив для них індекси. Ви можете налаштувати це, викликавши метод Schema :: defaultStringLength у своєму AppServiceProvider:

use Illuminate\Support\Facades\Schema;

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    Schema::defaultStringLength(191);
}

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

Довідка з блогу: https://www.scratchcode.io/specified-key-too-long-error-in-laravel/

Довідка з офіційної документації на laravel: https://laravel.com/docs/5.7/migramigra


0

Якщо ви створюєте щось на кшталт:

CREATE TABLE IF NOT EXISTS your_table (
  id int(7) UNSIGNED NOT NULL AUTO_INCREMENT,
  name varchar(256) COLLATE utf8mb4_bin NOT NULL,
  PRIMARY KEY (id),
  UNIQUE KEY name (name)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ROW_FORMAT=FIXED;

це має бути щось на кшталт

CREATE TABLE IF NOT EXISTS your_table (
      id int(7) UNSIGNED NOT NULL AUTO_INCREMENT,
      name varchar(256) COLLATE utf8mb4_bin NOT NULL,
      PRIMARY KEY (id)
    ) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ROW_FORMAT=FIXED;

але вам потрібно перевірити унікальність цього стовпця з коду або додати новий стовпець у вигляді MD5 або SHA1 колонки varchar


3
Тоді ваш унікальний ключ загубився. Я думаю, що кращий спосіб - просто скоротити довжину імені до 191.
haudoing

1
Навіщо програмно перевіряти на унікальність, якщо вона є рідною функцією БД?
Paweł Tomkiel

0

Через обмеження префікса ця помилка станеться. 767 байт - заявлене обмеження префікса для таблиць InnoDB у версіях MySQL до 5.7. Це 1000 байтів для таблиць MyISAM. У MySQL версії 5.7 і вище цей ліміт був збільшений до 3072 байт.

Виконавши таке в сервісі, що дає помилку, має вирішити вашу проблему. Це потрібно запустити в MYSQL CLI.

SET GLOBAL innodb_file_format=Barracuda;
SET GLOBAL innodb_file_per_table=on;
SET GLOBAL innodb_large_prefix=on;

-1

Зміна CHARSET поля індексу, що скаржиться, на "latin1",
тобто ALTER TABLE tbl CHANGE myfield myfield varchar (600) CHARACTER SET latin1 DEFAULT NULL;
latin1 бере один байт для одного символу замість чотирьох


5
А що, якщо він спробує вставити символи, які не є латинськими1 ?
Paweł Tomkiel

4
Це найгірше, що потрібно зробити. Ніколи цього не роби.
Себас

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

Мені довелося підкреслити це, оскільки використання latin1 не є рішенням у 2016AD. У мене все ще є жахливі кошмари про час, коли нам довелося перетворити базу даних з latin1 в utf8 ще в 2007 році. Не дуже. Зовсім.
Ставка Ламед

У мене була така ж проблема з унікальним індексом у двох стовпцях, де я зберігаю біткойн-адреси та ідентифікатори транзакцій. Це завжди будуть символи ASCII, тому в цих стовпцях я буду використовувати latin1. Оголошення.
alexg

-2

Якщо ви innodb_log_file_sizeнещодавно змінилися , спробуйте відновити попереднє значення, яке працювало.

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