# 1071 - Указанный ключ был слишком длинным; максимальная длина ключа 1000 байтов - PullRequest
78 голосов
/ 05 января 2012

Я знаю, что на вопросы с таким названием уже давались ответы, но, пожалуйста, продолжайте читать. Я прочитал внимательно все остальные вопросы / ответы по этой ошибке, прежде чем писать.

Я получаю вышеуказанную ошибку для следующего запроса:

CREATE TABLE IF NOT EXISTS `pds_core_menu_items` (
  `menu_id` varchar(32) NOT NULL,
  `parent_menu_id` int(32) unsigned DEFAULT NULL,
  `menu_name` varchar(255) DEFAULT NULL,
  `menu_link` varchar(255) DEFAULT NULL,
  `plugin` varchar(255) DEFAULT NULL,
  `menu_type` int(1) DEFAULT NULL,
  `extend` varchar(255) DEFAULT NULL,
  `new_window` int(1) DEFAULT NULL,
  `rank` int(100) DEFAULT NULL,
  `hide` int(1) DEFAULT NULL,
  `template_id` int(32) unsigned DEFAULT NULL,
  `alias` varchar(255) DEFAULT NULL,
  `layout` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`menu_id`),
  KEY `index` (`parent_menu_id`,`menu_link`,`plugin`,`alias`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

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

Любая подсказка приветствуется.

Я использую phpMyAdmin.

Ответы [ 7 ]

132 голосов
/ 05 января 2012

Как говорит @Devart, общая длина вашего индекса слишком велика.

Краткий ответ: в любом случае вы не должны индексировать такие длинные столбцы VARCHAR, потому что индекс будет очень громоздким и неэффективным.

Лучше всего использовать индексы префиксов , поэтому вы индексируете только левую подстроку данных. Большинство ваших данных в любом случае будет намного короче, чем 255 символов.

Вы можете объявить длину префикса для каждого столбца при определении индекса. Например:

...
KEY `index` (`parent_menu_id`,`menu_link`(50),`plugin`(50),`alias`(50))
...

Но какова лучшая длина префикса для данного столбца? Вот метод, чтобы узнать:

SELECT
 ROUND(SUM(LENGTH(`menu_link`)<10)*100/COUNT(`menu_link`),2) AS pct_length_10,
 ROUND(SUM(LENGTH(`menu_link`)<20)*100/COUNT(`menu_link`),2) AS pct_length_20,
 ROUND(SUM(LENGTH(`menu_link`)<50)*100/COUNT(`menu_link`),2) AS pct_length_50,
 ROUND(SUM(LENGTH(`menu_link`)<100)*100/COUNT(`menu_link`),2) AS pct_length_100
FROM `pds_core_menu_items`;

В нем указывается доля строк, которые имеют не более заданной длины строки в столбце menu_link. Вы могли бы видеть вывод как это:

+---------------+---------------+---------------+----------------+
| pct_length_10 | pct_length_20 | pct_length_50 | pct_length_100 |
+---------------+---------------+---------------+----------------+
|         21.78 |         80.20 |        100.00 |         100.00 |
+---------------+---------------+---------------+----------------+

Это говорит о том, что 80% ваших строк содержат менее 20 символов, а все ваши строки - менее 50 символов. Поэтому нет необходимости индексировать больше, чем длина префикса 50, и, конечно, нет необходимости индексировать полную длину 255 символов.

PS: типы данных INT(1) и INT(32) указывают на другое недоразумение о MySQL. Числовой аргумент не влияет на хранение или диапазон значений, допустимых для столбца. INT всегда 4 байта, и он всегда допускает значения от -2147483648 до 2147483647. Числовой аргумент - это заполнение значений во время отображения, которое не действует, если вы не используете опцию ZEROFILL.

25 голосов
/ 05 января 2012

Эта ошибка означает, что длина индекса index превышает 1000 байтов. MySQL и механизмы хранения могут иметь это ограничение. У меня похожая ошибка на MySQL 5.5 - «Указанный ключ был слишком длинным; Максимальная длина ключа составляет 3072 байта при запуске этого скрипта:

CREATE TABLE IF NOT EXISTS test_table1 (
  column1 varchar(500) NOT NULL,
  column2 varchar(500) NOT NULL,
  column3 varchar(500) NOT NULL,
  column4 varchar(500) NOT NULL,
  column5 varchar(500) NOT NULL,
  column6 varchar(500) NOT NULL,
  KEY `index` (column1, column2, column3, column4, column5, column6)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

UTF8 является многобайтовым, и длина ключа вычисляется таким образом - 500 * 3 * 6 = 9000 байт.

Но обратите внимание, следующий запрос работает!

CREATE TABLE IF NOT EXISTS test_table1 (
  column1 varchar(500) NOT NULL,
  column2 varchar(500) NOT NULL,
  column3 varchar(500) NOT NULL,
  column4 varchar(500) NOT NULL,
  column5 varchar(500) NOT NULL,
  column6 varchar(500) NOT NULL,
  KEY `index` (column1, column2, column3, column4, column5, column6)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

... поскольку я использовал CHARSET = latin1, в этом случае длина ключа составляет 500 * 6 = 3000 байт.

9 голосов
/ 04 апреля 2014

выполнить этот запрос перед созданием или изменением таблицы.

SET @@global.innodb_large_prefix = 1;

это установит максимальную длину ключа в 3072 байта

6 голосов
/ 05 июня 2018

У меня была эта проблема, и я решил ее следующим образом:

Причина

Существует известная ошибка в MySQL, связанная с MyISAM, символом UTF8. установить и индексы, которые вы можете проверить здесь.

Разрешение

  • Убедитесь, что MySQL настроен с механизмом хранения InnoDB.

  • Измените механизм хранения, используемый по умолчанию, чтобы новые таблицы всегда создавались соответствующим образом:

    set GLOBAL storage_engine='InnoDb';

  • Для MySQL 5.6 и более поздних версий используйте следующее:

    SET GLOBAL default_storage_engine = 'InnoDB';

  • И, наконец, убедитесь, что вы следуете инструкциям, приведенным в Миграция на MySQL .

Ссылка

3 голосов
/ 29 ноября 2012

Этот предел размера индекса кажется больше на 64-разрядных сборках MySQL.

Я нарушал это ограничение, пытаясь выгрузить нашу базу данных dev и загрузить ее на локальный виртуальный компьютер VMWare.Наконец я понял, что удаленный сервер разработки был 64-битным, и я создал 32-битный вирт.Я только что создал 64-битную виртуальную машину и смог загрузить базу данных локально.

2 голосов
/ 05 февраля 2016

Я только что обошел эту ошибку, просто изменив значения «длины» в исходной базе данных до общего значения около 1000, изменив ее структуру, а затем экспортировав ее на сервер.:)

1 голос
/ 05 сентября 2018

Я столкнулся с той же проблемой, использованной ниже для ее решения.

При создании БД вы можете использовать кодировку utf-8

напримерcreate database my_db character set utf8 collate utf8_bin;

...