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

452

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

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
  • 3
    Поскольку это не 520 байт, а скорее 2080 байт, что намного превышает 767 байт, вы можете использовать column1 varchar (20) и column2 varchar (170). если вы хотите использовать символ / байт, используйте latin1
  • 2
    Я думаю, что ваш расчет здесь немного ошибочен. mysql использует 1 или 2 дополнительных байта для записи длины значений: 1 байт, если максимальная длина столбца составляет 255 байт или меньше, 2, если он длиннее 255 байт. для кодировки utf8_general_ci требуется 3 байта на символ, поэтому varchar (20) использует 61 байт, varchar (500) использует 1502 байта в общей сложности 1563 байта
Показать ещё 4 комментария
Теги:
byte
varchar
mysql-error-1071

29 ответов

338
Лучший ответ

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 ограничение.

  • 4
    Чтобы применить, указав подмножество столбца, а не всю сумму. Хорошее решение
  • 0
    @OMGPonies: Вы случайно не знаете, имеют ли DB2 / MSSQL / Oracle такое же ограничение на размер индекса? Например HSQL не имеет такого ограничения ...
Показать ещё 9 комментариев
383

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

  • 230
    Количество разрешенных символов зависит только от вашего набора символов. UTF8 может использовать до 3 байтов на символ, utf8mb4 до 4 байтов, а latin1 только 1 байт. Таким образом, для utf8 длина вашего ключа ограничена 255 символами, так как 3*255 = 765 < 767 .
  • 7
    Это спасло меня от многих разочарований - спасибо. Это должен быть принятый ответ IMO, учитывая, что пользователь использует InnoDB, утверждая, что он достиг ограничения 767b.
Показать ещё 6 комментариев
248

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

  • INNODB utf8 VARCHAR(255)
  • INNODB utf8mb4 VARCHAR(191)
  • 22
    Это лучший ответ. Просто, прямо в точку и также включает предел utf8mb4 (который является наиболее используемой кодировкой для новых баз данных, так как он принимает эмодзи / и т. Д.).
  • 5
    потому что 767/4 ~ = 191 и 767/3 ~ = 255
Показать ещё 5 комментариев
136

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

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

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

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

SET @@global.innodb_large_prefix = 1;

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

  • 2
    Есть ли какие-либо недостатки при переходе на innodb_large_prefix глобально? И является ли эта БД "глобальной" или все БД ПОЛНОСТЬЮ ГЛОБАЛЬНЫ?
  • 4
    Применяется только при использовании нестандартных форматов строк. См. Dev.mysql.com/doc/refman/5.5/en/… . В частности, «Включите эту опцию, чтобы разрешить префиксы ключа индекса длиной более 767 байт (до 3072 байт) для таблиц InnoDB, которые используют форматы строк DYNAMIC и COMPRESSED». Формат строки по умолчанию не изменяется.
Показать ещё 4 комментария
38

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

  • 0
    Я использую utf8_general_ci.
  • 8
    Если это UTF8, символ может использовать до 4 байтов, поэтому столбец из 20 символов составляет 20 * 4 + 1 байт, а столбец из 500 символов - 500 * 4 + 2 байта.
Показать ещё 5 комментариев
28

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

  • 3
    кто что сказал про php, это вопрос БД
  • 9
    @ BojanPetkovic, ну, я только что пришел из проблемы Laravel, и этот ответ фактически решил мою проблему.
Показать ещё 4 комментария
22

Я думаю, что 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, чтобы ускорить поиск.
  • 0
    Это добилось цели. У меня был varchar (256), и я должен был изменить его на varchar (250).
17
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 байт.

15

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

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

  • Откройте клиент 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 на этом сервере. Вы не можете заставить его работать там.

  • 0
    если вы все еще видите ошибку после ввода вышеуказанного запроса, попробуйте перейти к «phpmyadmin»> установить «collation» по своему усмотрению (для меня я использую «utf8_general_ci»)> нажать «применить» (даже если его уже utf8)
15

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

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

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

Изображение 829

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

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

В конце дня, если вы хотите иметь уникальный индекс в поле, все содержимое поля должно вписываться в индекс. Для utf8mb4 это означает сокращение длины полей VARCHAR до 191 символа или меньше. Если вам не нужна utf8mb4 для этой таблицы или поля, вы можете вернуть ее обратно в utf8 и сохранить свои длины длины.

7

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

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

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

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

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

Для 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;
  • Готово
  • 0
    Я не могу найти это: 6. Установите значение параметра innodb_default_row_format в DYNAMIC.
  • 0
    если я использую set global innodb_default_row_format = DYNAMIC; Я вижу это сообщение: ОШИБКА 1193 (HY000): неизвестная системная переменная 'innodb_default_row_format'
Показать ещё 5 комментариев
5

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

4

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

varchar(200) 

заменено на

varchar(191)

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

3

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

2

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

Шаги к следованию

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

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

2

В соответствии с приведенным ниже столбцом эти 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
1

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

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

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

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
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;
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

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

  • 3
    А что если он попытается вставить нелатинские символы 1?
  • 2
    Это худшее, что нужно сделать. Никогда не делай этого.
Показать ещё 4 комментария
-1

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

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

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

-3

Если вы запускаете Laravel (теперь laravel по умолчанию использует 4-байтовый Unicode, который вызывает это), вы можете решить эту проблему, изменив следующие строки в config/database.php из

'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',

 к

'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
  • 0
    utf8mb4 должна быть кодировкой по умолчанию в наше время. В противном случае вы не будете поддерживать новых персонажей.
  • 0
    Вы не будете поддерживать смайлики при переключении с utf8 с utf8mb4 .

Ещё вопросы

Сообщество Overcoder
Наверх
Меню