Когда я выполнил следующую команду:
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
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 ограничение.
Если у кого-то возникают проблемы с INNODB/Utf-8, пытающимся поместить индекс UNIQUE
в поле VARCHAR(256)
, переключите его на VARCHAR(255)
. Кажется, 255 является ограничением.
3*255 = 765 < 767
.
Когда вы достигнете предела. Установите следующее.
utf8
VARCHAR(255)
utf8mb4
VARCHAR(191)
utf8mb4
(который является наиболее используемой кодировкой для новых баз данных, так как он принимает эмодзи / и т. Д.).
MySQL принимает наихудший случай для числа байтов на символ в строке. Для кодировки MySQL 'utf8' это 3 байта на символ, поскольку эта кодировка не допускает символов за пределами U+FFFF
. Для кодировки MySQL 'utf8mb4' это 4 байта на символ, так как то, что MySQL вызывает на самом деле UTF-8.
Итак, если вы используете "utf8", ваш первый столбец займет 60 байт индекса, а второй второй - 1500.
запустите этот запрос перед запросом:
SET @@global.innodb_large_prefix = 1;
это увеличит предел до 3072 bytes
.
Какую кодировку символов вы используете? Некоторые наборы символов (например, UTF-16 и т.д.) Используют более одного байта на символ.
20 * 4 + 1
байт, а столбец из 500 символов - 500 * 4 + 2
байта.
Решение для 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
для вашей базы данных. Обратитесь к документации базы данных для получения инструкций о том, как правильно включить эту опцию.
Я думаю, что 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 символ.
[A-z0-9\-]
, я использовал latin1_general_ci
, который использует только один байт на символ, поэтому столбец может иметь длину 767 байт.UNIQUE
, чтобы гарантировать, что значения SEO уникальны. Я бы также добавил индекс KEY
в исходную колонку SEO, чтобы ускорить поиск.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 байт.
Ответ на вопрос о том, почему вы получили сообщение об ошибке, уже получили ответы от многих пользователей здесь. Мой ответ о том, как исправить и использовать его как есть.
Обратитесь к этой ссылке.
use my_database_name;
Изменена база данных
set global innodb_large_prefix=on;
Query OK, 0 строк (0.00 sec)
set global innodb_file_format=Barracuda;
Запрос ОК, 0 строк затронуты (0,02 сек)
Проблема этого исправления заключается в том, что вы экспортируете db на другой сервер (например, с localhost на реальный хост), и вы не можете использовать командную строку MySQL на этом сервере. Вы не можете заставить его работать там.
вы можете добавить столбец md5 длинных столбцов
Мы столкнулись с этой проблемой при попытке добавить индекс 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 и сохранить свои длины длины.
Вот мой оригинальный ответ:
Я просто сбрасываю базу данных и воссоздаю вот так, и ошибка исчезла:
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
Я сделал несколько поисков по этой теме, наконец, получил пользовательские изменения
Для Workbench MySQL 6.3.7 Версия Доступна графическая межфазная
Для версий ниже 6.3.7 прямые параметры недоступны, поэтому вам нужно перейти с командной строкой
set global innodb_default_row_format = DYNAMIC;
Я вижу это сообщение: ОШИБКА 1193 (HY000): неизвестная системная переменная 'innodb_default_row_format'
измените свою сортировку. Вы можете использовать utf8_general_ci, который поддерживает почти все
Я исправил эту проблему с:
varchar(200)
заменено на
varchar(191)
все varchar, у которых есть больше чем 200, заменяют их 191 или устанавливают их текст.
Простое изменение utf8mb4
на utf8
при создании таблиц решило мою проблему. Например: CREATE TABLE... DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE... DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
,
Для Laravel 5,7 или 5,6
Шаги к следованию
App\Providers\AppServiceProvider.php
.use Illuminate\Support\Facades\Schema;
в топе.Schema::defaultStringLength(191);
это все, наслаждайтесь.
В соответствии с приведенным ниже столбцом эти 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
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
В моем случае у меня была эта проблема, когда я делал резервные копии базы данных, используя символы ввода/вывода перенаправления 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 байт" просто исчезла.
Я нашел этот запрос полезным при обнаружении столбцов с индексом, нарушающим максимальную длину:
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')
Пожалуйста, проверьте, если sql_mode
похож
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
если это так, измените на
sql_mode=NO_ENGINE_SUBSTITUTION
ИЛИ ЖЕ
перезагрузите сервер, изменив файл my.cnf (добавив следующее)
innodb_large_prefix=on
Из-за ограничений префикса эта ошибка произойдет. 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;
Если вы создаете что-то вроде:
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.
Измените CHARSET в поле индекса жалобы на "latin1"
то есть ALTER TABLE tbl CHANGE myfield myfield varchar (600) CHARACTER SET latin1 DEFAULT NULL,
latin1 принимает один байт для одного символа вместо четырех
Для меня проблема с ключом # 1071 - слишком длинная, максимальная длина ключа - 767 байт, решена после изменения комбинации primarykey/uniquekey, ограничивая размер столбца на 200.
ALTER TABLE `mytable` ADD UNIQUE (
`column1` (200) ,
`column2` (200)
);
Если вы недавно изменили innodb_log_file_size
, попробуйте восстановить предыдущее значение, которое сработало.
Если вы запускаете Laravel (теперь laravel по умолчанию использует 4-байтовый Unicode, который вызывает это), вы можете решить эту проблему, изменив следующие строки в config/database.php из
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
 к
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
utf8
с utf8mb4
.