# 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

Ответ 1

767 bytes - это указанное префиксное ограничение для таблиц InnoDB в MySQL версии 5.6 (и предыдущих версиях). Это 1000 байтов для таблиц MyISAM. В MySQL версии 5.7 и выше этот предел был увеличен до 3072 байт.

Вы также должны знать, что если вы установите индекс в большом поле char или varchar, которое закодировано в utf8mb4, вам необходимо разделить максимальную длину префикса max 767 байтов (или 3072 байта) на 4, что приведет к 191. Это связано с тем, что максимальная длина символа utf8mb4 равна четырем байтам. Для символа utf8 это будет три байта, в результате чего максимальная длина префикса индекса будет равна 254.

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

Другой вариант (в соответствии с ответом на эту проблему) заключается в том, чтобы получить подмножество столбца, а не всю сумму, то есть:

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

Подчеркните, как вам нужно получить ключ для применения, но мне интересно, стоит ли рассматривать вашу модель данных относительно этого объекта, чтобы увидеть, есть ли улучшения, которые позволят вам реализовать намеченные бизнес-правила, не нажимая на MySQL ограничение.

Ответ 2

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

Ответ 3

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

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

Ответ 4

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

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

Ответ 5

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

SET @@global.innodb_large_prefix = 1;

это увеличит предел до 3072 bytes.

Ответ 6

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

Ответ 7

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

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

Ответ 8

Я думаю, что 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 символ.


Есть два решения этой проблемы, если вам нужно использовать более длинный столбец, чем предел:

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

Ответ 9

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

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

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

Изменена база данных

  1. set global innodb_large_prefix=on;

Query OK, 0 строк (0.00 sec)

  1. set global innodb_file_format=Barracuda;

Запрос ОК, 0 строк затронуты (0,02 сек)

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

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

Ответ 10

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, primary key. Просто не нарушайте 767 байт.

Ответ 11

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

Ответ 12

Мы столкнулись с этой проблемой при попытке добавить индекс 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 и сохранить свои длины длины.

Ответ 13

Вот мой оригинальный ответ:

Я просто сбрасываю базу данных и воссоздаю вот так, и ошибка исчезла:

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

Ответ 14

Я исправил эту проблему с:

varchar(200) 

заменено на

varchar(191)

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

Ответ 15

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

Ответ 16

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

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

  • Запустите Workbench и выберите соединение.
  • Перейдите в "Управление" или "Экземпляр" и выберите "Файл параметров".
  • Если Workbench запросит разрешение на чтение файла конфигурации, а затем разрешите его, дважды нажав OK.
  • На центральном месте появится окно файла параметров администратора.
  • Перейдите на вкладку InnoDB и проверьте файл innodb_large_prefix, если он не отмечен в разделе "Общие".
  • установите значение параметра innodb_default_row_format в значение DYNAMIC.

Для версий ниже 6.3.7 прямые параметры недоступны, поэтому вам нужно перейти с командной строкой

  • Запустите CMD в качестве администратора.
  • Перейти к директору, где установлен сервер mysql. Большинство случаев "C:\Program Files\MySQL\MySQL Server 5.7\bin", поэтому команда "CD \" "cd Program Files\MySQL\MySQL Server 5.7\bin".
  • Теперь выполнить команду mysql -u userName -p databasescheema Теперь он запросил пароль соответствующего пользователя. Предоставьте пароль и введите запрос mysql.
  • Мы должны установить некоторые глобальные настройки, чтобы ввести следующие команды по одному установить глобальный innodb_large_prefix = on; установить глобальный innodb_file_format = barracuda; установить глобальный innodb_file_per_table = true;
  • Теперь, в конце концов, мы должны изменить ROW_FORMAT требуемой таблицы по умолчанию ее COMPACT, мы должны установить ее в DYNAMIC.
  • используйте следующую команду alter table table_name ROW_FORMAT = DYNAMIC;
  • Готово

Ответ 17

измените свою сортировку. Вы можете использовать utf8_general_ci, который поддерживает почти все

Ответ 18

Для Laravel 5,7 или 5,6 или 5,8

Шаги, чтобы следовать

  1. Перейдите в App\Providers\AppServiceProvider.php.
  2. Добавьте это к поставщику, use Illuminate\Support\Facades\Schema; в топе.
  3. Внутри загрузочной функции Добавьте эту Schema::defaultStringLength(191);

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

Ответ 19

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

Ответ 20

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

enter image description here

Ответ 21

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

В MySQL utf8 charset использует максимум 3 байта для каждого символа. Таким образом, ему нужно будет выделить 500 * 3 = 1500 байт, что намного больше, чем позволяет 767 байт MySQL. Вот почему вы получаете эту ошибку 1071.

Другими словами, вам нужно вычислить количество символов, основанное на представлении байтов набора символов, поскольку не каждая кодировка представляет собой однобайтовое представление (как вы предполагали). I.E. utf8 в MySQL использует не более 3 байтов на символ, 767/3≈255 символов, а для utf8mb4 - не более 4-байтового представления, 767/4≈191 символов.

Также известно, что MySQL

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

Ответ 22

Пожалуйста, проверьте, если sql_mode похож

sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

если это так, измените на

sql_mode=NO_ENGINE_SUBSTITUTION

ИЛИ ЖЕ

перезагрузите сервер, изменив файл my.cnf (добавив следующее)

innodb_large_prefix=on

Ответ 23

Я нашел этот запрос полезным при обнаружении столбцов с индексом, нарушающим максимальную длину:

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')

Ответ 24

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

Ответ 25

Если вы создаете что-то вроде:

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.

Ответ 26

В моем случае у меня была эта проблема, когда я делал резервные копии базы данных, используя символы ввода/вывода перенаправления 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 байт" просто исчезла.

Ответ 27

Из-за ограничений префикса эта ошибка произойдет. 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;

Ответ 28

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

Ссылка из Официальной документации Laravel: https://laravel.com/docs/5.7/migrations

Ответ 29

Чтобы исправить это, это работает для меня как шарм.

ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;

Ответ 30

Для меня проблема с ключом # 1071 - слишком длинная, максимальная длина ключа - 767 байт, решена после изменения комбинации primarykey/uniquekey, ограничивая размер столбца на 200.

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