#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
38 ответов
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.
Когда вы достигнете предела. Установите следующее.
- INNODB
utf8
VARCHAR(255)
- INNODB
utf8mb4
VARCHAR(191)
Если у кого-то возникают проблемы с INNODB / Utf-8, попробуйте поставить UNIQUE
индекс на VARCHAR(256)
поле, переключите его на VARCHAR(255)
, Кажется, 255 является ограничением.
MySQL предполагает наихудший случай для количества байтов на символ в строке. Для кодировки MySQL UTF8 это 3 байта на символ, так как эта кодировка не допускает символы за пределами U+FFFF
, Для кодировки MySQL 'utf8mb4' это 4 байта на символ, так как именно это MySQL называет фактическим UTF-8.
Итак, если вы используете utf8, ваш первый столбец займет 60 байтов индекса, а второй - 1500.
Решение для 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
вариант для вашей базы данных. Обратитесь к документации вашей базы данных для получения инструкций о том, как правильно включить эту опцию.
Запустите этот запрос перед вашим запросом:
SET @@global.innodb_large_prefix = 1;
это увеличит лимит до 3072 bytes
,
Какую кодировку символов вы используете? Некоторые наборы символов (например, UTF-16 и т. Д.) Используют более одного байта на символ.
Я думаю, что 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 строку статьи, так как я использую только[A-z0-9\-]
персонажи для SEO я использовалlatin1_general_ci
который использует только один байт на символ, поэтому столбец может иметь длину 767 байтов. - Создайте хеш из вашего столбца и используйте уникальный индекс только для этого
Другой вариант для меня был создать еще один столбец, который будет хранить хэш SEO, этот столбец будет иметьUNIQUE
ключ к тому, чтобы значения SEO были уникальными. Я бы тоже добавилKEY
индекс до оригинальной колонки SEO, чтобы ускорить поиск.
Ответ о том, почему вы получаете сообщение об ошибке, уже был дан ответ многим пользователям здесь. Мой ответ о том, как исправить и использовать его как есть.
- Откройте клиент MySQL (или клиент MariaDB). Это инструмент командной строки.
- Он спросит ваш пароль, введите ваш правильный пароль.
- Выберите вашу базу данных с помощью этой команды
use my_database_name;
База данных изменена
set global innodb_large_prefix=on;
Запрос в порядке, затронуто 0 строк (0, 00 с)
set global innodb_file_format=Barracuda;
Запрос в порядке, затронуто 0 строк (0, 02 с)
- Перейдите в свою базу данных на phpMyAdmin или что-то подобное для простоты управления. > Выберите базу данных> Просмотр структуры таблицы> Перейдите на вкладку Операции. > Измените ROW_FORMAT на DYNAMIC и сохраните изменения.
- Перейдите на вкладку структуры таблицы> Нажмите на уникальную кнопку.
- Готово. Теперь оно не должно иметь ошибок.
Проблема этого исправления заключается в том, что вы экспортируете db на другой сервер (например, с локального хоста на реальный хост) и не можете использовать командную строку MySQL на этом сервере. Вы не можете заставить это работать там.
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 байт.
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)
Для Laravel 5,6
Шаги к следованию
- Идти к
App\Providers\AppServiceProvider.php
, - Добавить это к провайдеру
use Illuminate\Support\Facades\Schema;
в топе. - В функции загрузки Добавить это
Schema::defaultStringLength(191);
это все, наслаждайтесь.
Я исправил эту проблему с:
varchar(200)
заменено на
varchar(191)
все varchar, у которых есть больше чем 200, заменяют их 191 или устанавливают их текст.
Мы столкнулись с этой проблемой при попытке добавить индекс 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
Вот:
Это хорошо, потому что обычные индексы просто используются, чтобы помочь MySQL быстрее искать ваши данные. Целое поле не нужно индексировать.
Итак, почему MySQL усекает индекс автоматически для обычных индексов, но выдает явную ошибку при попытке сделать это для уникальных индексов? Что ж, для того, чтобы MySQL мог выяснить, существует ли уже добавляемое или обновляемое значение, ему нужно на самом деле индексировать все значение, а не только его часть.
В конце дня, если вы хотите иметь уникальный индекс для поля, все содержимое поля должно вписываться в индекс. Для utf8mb4 это означает уменьшение длины поля VARCHAR до 191 символа или менее. Если вам не нужен utf8mb4 для этой таблицы или поля, вы можете вернуть его обратно к utf8 и сохранить свои поля длиной 255.
Вот мой оригинальный ответ:
Я просто сбрасываю базу данных и воссоздаю вот так, и ошибка исчезла:
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-character-set-to-utf8mb4
Чтобы исправить это, это работает для меня как шарм.
ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;
Я сделал некоторые поиски по этой теме, наконец, получил некоторые пользовательские изменения
Для 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.
- Мы должны установить некоторые глобальные настройки, вводить команды ниже по одному set global innodb_large_prefix=on; установить глобальный innodb_file_format=barracuda; установить глобальный innodb_file_per_table=true;
- Теперь, наконец, мы должны изменить ROW_FORMAT требуемой таблицы, по умолчанию ее COMPACT, мы должны установить ее в DYNAMIC.
- используйте следующую команду alter table table_name ROW_FORMAT=DYNAMIC;
- Готово
Длина индекса и 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
Это решило мою проблему
ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;
Измените свою сортировку. Вы можете использовать utf8_general_ci, который поддерживает почти все
Просто меняется utf8mb4
в utf8
При создании таблиц решена моя проблема. Например: CREATE TABLE ... DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
в CREATE TABLE ... DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
,
Исходя из приведенного ниже столбца, эти два столбца переменной строки используют utf8_general_ci
сопоставление (utf8
подразумевается charset).
В MySQL utf8
charset использует максимум 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
Я нашел этот запрос полезным для определения того, какие столбцы имеют индекс, нарушающий максимальную длину:
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')
В моем случае у меня была эта проблема, когда я делал резервные копии базы данных, используя символы ввода / вывода перенаправления 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 байт" просто исчезла.
Эта проблема
В MySQL есть ограничения на максимальную длину ключа.
- InnoDB - максимальная длина ключа составляет 1536 байт (для размера страницы 8 КБ) и 768 (для размера страницы 4 КБ) (Источник: Dev.MySQL.com).
- MyISAM - максимальная длина ключа составляет 1000 байт (Source Dev.MySQL.com).
Они считаются байтами! Таким образом, для сохранения в ключе символа UTF-8 может потребоваться более одного байта.
Следовательно, у вас есть только два немедленных решения:
- Индексируйте только первые n-е символы типа текста.
- Создать
FULL TEXT
поиск - все будет доступно для поиска в тексте аналогично ElasticSearch
Индексирование первых N символов текстового типа
Если вы создаете таблицу, используйте следующий синтаксис для индексации первых 255 символов некоторого поля:
KEY
sometextkey
(
SomeText
(255))
. Вот так:
CREATE TABLE `MyTable` (
`id` int(11) NOT NULL auto_increment,
`SomeText` TEXT NOT NULL,
PRIMARY KEY (`id`),
KEY `sometextkey` (`SomeText`(255))
);
Если у вас уже есть таблица, вы можете добавить уникальный ключ в поле с помощью:
ADD UNIQUE(
ConfigValue
(20));
. Вот так:
ALTER TABLE
MyTable
ADD UNIQUE(`ConfigValue`(20));
Если имя поля не является зарезервированным ключевым словом MySQL, то обратные кавычки (``) вокруг имени поля не обязательны.
Создание ПОЛНОГО ТЕКСТА поиска
Полнотекстовый поиск позволит вам искать всю ценность вашего
TEXT
поле. Он будет выполнять сопоставление всего слова, если вы используете
NATURAL LANGUAGE MODE
, или частичное сопоставление слов, если вы используете один из других режимов. Дополнительную информацию о параметрах FullText можно найти здесь: Dev.MySQL.com
Создайте свою таблицу с текстом и добавьте полнотекстовый индекс ...
ALTER TABLE
MyTable
ADD FULLTEXT INDEX
`SomeTextKey` (`SomeTextField` DESC);
Затем выполните поиск в своей таблице так ...
SELECT
MyTable.id, MyTable.Title,
MATCH
(MyTable.Text)
AGAINST
('foobar' IN NATURAL LANGUAGE MODE) AS score
FROM
MyTable
HAVING
score > 0
ORDER BY
score DESC;
Из-за ограничений префикса эта ошибка произойдет. 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;
Пожалуйста, проверьте, если sql_mode
как
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
если это так, измените на
sql_mode=NO_ENGINE_SUBSTITUTION
ИЛИ ЖЕ
перезагрузите сервер, изменив файл my.cnf (добавив следующее)
innodb_large_prefix=on
У меня есть изменения с varchar на nvarchar, у меня работает.