# 1071 - Указанный ключ был слишком длинным; максимальная длина ключа 767 байт


563

Когда я выполнил следующую команду:

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 байт, вы можете использовать column1 varchar (20) и column2 varchar (170). если вы хотите использовать символ / байт, используйте latin1
Rahly

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

3
mysql> выбрать maxlen, имя_символа_символа из information_schema.character_sets, где имя_символа_символа в ('latin1', 'utf8', 'utf8mb4'); Макслен | имя_символа ------ | ------------------- 1 | latin1 ------ | ------------------- 3 | utf8 ------ | ------------------- 4 | UTF8MB4
LOVOVIC10

15
'если вам нужен символ / байтовый эквивалент, используйте latin1' Пожалуйста , не делайте этого . Latin1 действительно, действительно отстой. Вы будете сожалеть об этом.
Стейн де Витт

Обратитесь к stackoverflow.com/a/52778785/2137210 для решения
Pratik

Ответы:


490

767 байт - заявленное ограничение префикса для таблиц InnoDB в MySQL версии 5.6 (и предыдущих версиях). Это длина 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
Это не объясняет, почему поля значительно ниже предела длины превышают предел длины ...
Cerin

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

8
Это может быть проблемой. Например: у меня есть имя поля (255) и я добавляю уникальное имя в это поле с именем (191), так как я использую utf8mb4. Если у меня есть мой пользователь, добавьте его имя с помощью 'IJUE3ump5fiUuCi16jSofYS234MLschW4wsIktKiBrTPOTKBK6Vteh5pNuz1tKjy ... aO500mlJs', а другой пользователь добавит свое имя с этим 'IJUE3ump5fiUKKYTUKYBYKYBKYTKW6STKW4STKW4STKW2STKHYKYKYTKW3STKW3STKH5 Он должен пройти проверку, не застряв при повторной записи.
ви

29
Предел индекса составляет 767 байтов , а не символов. А так как utf8mb4набор символов Mysql (который остальной мир называет utf8) требует (максимум) 4 байта на символ, вы можете индексировать только до VARCHAR(191). utf8Набор символов Mysql (который остальной мир называет неработающим) требует максимум 3 байта на символ, поэтому, если вы используете его (чего не следует ), вы можете индексировать доVARCHAR(255)
Stijn de Witt

404

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


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

10
Это спасло меня от многих разочарований - спасибо. Это должен быть принятый ответ IMO, учитывая, что пользователь использует InnoDB, утверждая, что он достиг ограничения 767b.
TheCarver

8
Как заявил Стефан Эндруллис, это зависит от кодировки. Если вы используете UTF8, который использует 3 байта: 255x3 = 765, что ниже, чем предел 767, а 256x3 = 768, что выше. Но если вы используете UTF8mb4, его 255 * 4 = 1020, так что это не очень хорошее решение
Бернхард

25
Этот ответ правильный. Однако, если 255 действительно работает для вас, это означает, что вы используете Mysql utf8, который, к сожалению, не работает. Он может кодировать символы только в основной многоязычной плоскости. Вы получите проблемы с персонажами, выходящими за рамки этого. Например, те персонажи Emoji, которые они добавляли, выпадают из этого, я думаю. Поэтому вместо того, чтобы переключаться на VARCHAR(255), переключаться на VARCHAR(191) и переключать кодировку на utf8mb4(что на самом деле просто utf8, но MySql хотел сохранить обратно. Compat).
Стейн де Витт

1
Не полезно для моего многоколоночного уникального ограничения. Это также не будет работать для ограничения уникальности многоколоночного OP. (даст общий размер 825 байт)
Barett

353

Когда вы достигнете предела. Установите следующее.

  • INNODB utf8 VARCHAR(255)
  • INNODB utf8mb4 VARCHAR(191)

34
Это лучший ответ. Просто, прямо в точку и также включает в себя utf8mb4ограничение (которое является наиболее используемой кодировкой для новых баз данных, так как она принимает эмодзи / и т. Д.).
Клаудио Холанда

10
потому что 767/4 ~ = 191 и
бухгалтер م

11
где и как его установить?
Динеш Санни

1
Да, указав ENGINE=InnoDB DEFAULT CHARSET=utf8в конце CREATE TABLEоператора, я смог получить VARCHAR(255)первичный ключ. Спасибо.
xonya

1
кто-то дает ему +1, чтобы превысить предел 191 :)
cagcak

147

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

Итак, если вы используете utf8, ваш первый столбец займет 60 байтов индекса, а второй - 1500.


4
- Что, по-видимому, означает, что при использовании utf8mb4 мне нужно установить для них (максимум) 191 как 191 * 4 = 764 <767.
Исаак

2
@ Исаак Да, именно так,
morganwahl

2
Я думаю, что это может быть правильный ответ, но не могли бы вы уточнить, что нужно сделать, чтобы исправить такую ​​проблему? По крайней мере, для MySQL нубов, как я?
Адам Грант

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

Уникальный индекс очень длинного столбца varchar встречается редко. Подумайте, зачем вам это нужно, потому что это может быть проблемой дизайна. Если вы просто хотите использовать индекс для поиска, рассмотрите поле «ключевые слова», которое умещается в пределах 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/…
cwd

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набор символов по умолчанию, который включает поддержку для хранения «emojis» в базе данных. Если вы используете версию MySQL, более раннюю, чем версия 5.7.7, или MariaDB, более раннюю, чем версия 10.2.2, вам может потребоваться вручную настроить длину строки по умолчанию, создаваемую миграциями, чтобы MySQL создавал для них индексы. Вы можете настроить это, вызвав Schema::defaultStringLengthметод внутри вашегоAppServiceProvider .

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


10
@ BojanPetkovic Ну, я только что пришел из проблемы Laravel, и этот ответ фактически решил мою проблему.
mkmnstr

Этот ответ великолепен. Но кто-нибудь знает, почему именно это работает?
UeliDeSchwert

1
Документация @Bobby Laravel дает объяснение в заголовке « Длина
Али Шаукат,

1
@Bobby Я обновил ответ. Я добавил объяснение, данное в документации laravel для этого исправления.
Али Шаукат

39

Какую кодировку символов вы используете? Некоторые наборы символов (например, UTF-16 и т. Д.) Используют более одного байта на символ.


8
Если это UTF8, символ может использовать до 4 байтов, поэтому столбец из 20 символов - это 20 * 4 + 1байты, а столбец из 500 символов - 500 * 4 + 2байты
Танатос

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, Оказывается , ваш сервер был asssuming 3 байта на символ, @ Арьян
Янтарный

21
@ Грег: Вы правы, но это следует уточнить: сам 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).
17

25

Ответ о том, почему вы получаете сообщение об ошибке, уже был дан ответ многим пользователям здесь. Мой ответ о том, как исправить и использовать его как есть.

Обратитесь с этой ссылки .

  1. Откройте клиент MySQL (или клиент MariaDB). Это инструмент командной строки.
  2. Он спросит ваш пароль, введите ваш правильный пароль.
  3. Выберите вашу базу данных с помощью этой команды use my_database_name;

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

  1. set global innodb_large_prefix=on;

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

  1. set global innodb_file_format=Barracuda;

Запрос в порядке, затронуто 0 строк (0,02 с)

  1. Перейдите в свою базу данных на phpMyAdmin или что-то подобное для простоты управления. > Выберите базу данных> Просмотр структуры таблицы > Перейдите на вкладку Операции . > Измените ROW_FORMAT на ДИНАМИЧНЫЙ и сохраните изменения.
  2. Перейти на вкладку структуры таблицы > Нажмите на уникальный кнопку « .
  3. Выполнено. Теперь оно не должно иметь ошибок.

Проблема этого исправления заключается в том, что вы экспортируете db на другой сервер (например, с локального хоста на реальный хост) и не можете использовать командную строку MySQL на этом сервере. Вы не можете заставить это работать там.


если вы все еще видите ошибку после ввода вышеуказанного запроса, попробуйте перейти к «phpmyadmin»> установить «collation» по своему усмотрению (для меня я использую «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 байт.


17

Замените utf8mb4на utf8в вашем файле импорта.

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


Почему именно это нужно делать? Кроме того, если у этого есть какие-либо недостатки (что я предполагаю), вы должны упомянуть об этом
Нико Хаас

16

Вы можете добавить столбец md5 длинных столбцов


Обратите внимание, что это не позволит вам сканировать диапазон по этим столбцам. Длина префикса в VARCHAR позволит вам сохранить эту черту, в то же время вызывая, возможно, ложные совпадения в индексе (а также сканирование и поиск строк для их устранения) (см. Принятый ответ). (Это по сути реализованный вручную хэш-индекс, который, к сожалению, MysQL не поддерживает с таблицами InnoDB.)
Thanatos

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

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: http://hanoian.com/content/index.php/24-automate-the-converting-a-mysql-database- Символьный набор к utf8mb4


Решил проблему с настройкой openmeetings (кстати, вы сохранили мою ночь :-)
Ludo

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)

все varchar, у которых есть больше чем 200, заменяют их 191 или устанавливают их текст.


Это то, что работало для меня тоже. У меня был varchar (250), но данные никогда не были такими длинными. Поменял его на varchar (100). Спасибо за идею :)
Арун Бэзил Лал

7

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

Для MySQL верстак 6.3.7 Версия Доступна графическая межфаза

  1. Запустите Workbench и выберите соединение.
  2. Перейдите в управление или Экземпляр и выберите Файл параметров.
  3. Если Workbench спросит у вас разрешение на чтение файла конфигурации, а затем разрешите его, дважды нажав OK.
  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 Program Files \ MySQL \ MySQL Server 5.7 \ bin".
  3. Теперь запустите команду mysql -u userName -p databasescheema Теперь он запрашивает пароль соответствующего пользователя. Введите пароль и введите приглашение MySQL.
  4. Мы должны установить некоторые глобальные настройки, вводить команды ниже по одному set global innodb_large_prefix = on; установить глобальный 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'
Адриан Сид

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

Я делаю это из CMD, потому что не вижу опцию в Workbench
Адриан Сид

1
Я вижу проблему, эта версия была введена в 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.
mahyard

2

Основываясь на приведенном ниже столбце, эти 2 столбца переменной строки используют параметры utf8_general_ciсортировки ( utf8подразумевается charset).

В MySQL utf8кодировка использует максимум 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 , который включает поддержку для хранения «emojis» в базе данных. Если вы используете версию 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/migrations


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.
Хаудинг

1
Зачем проверять уникальность программно, если это встроенная функция БД?
Павел Томкиэль

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?
Павел Томкиэль

4
Это худшее, что нужно сделать. Никогда не делай этого.
Себас

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

Я должен был понизить это, так как использование latin1 не является решением в 2016 году. У меня до сих пор ужасные кошмары о том, как в 2007 году нам пришлось конвертировать базу данных из латиницы в utf8. Не красиво Совсем.
Ставка Lamed

У меня была такая же проблема с уникальным индексом в двух столбцах, где я храню адреса биткойнов и идентификаторы транзакций. Это всегда будут символы ASCII, поэтому я буду использовать latin1 в этих столбцах. Upvoting.
alexg

-2

Если вы innodb_log_file_sizeнедавно изменились , попробуйте восстановить предыдущее значение, которое сработало.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.