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

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

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

436

Решение

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.

362

Другие решения

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

367

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

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

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

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

143

запустите этот запрос перед вашим запросом:

SET @@global.innodb_large_prefix = 1;

это увеличит лимит до 3072 bytes,

41

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

37

Решение для 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 вариант для вашего
база данных. Обратитесь к документации вашей базы данных для получения инструкций по
как правильно включить эту опцию.

29

Я думаю, что 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, чтобы ускорить поиск.
22
По вопросам рекламы [email protected]