# 1071 - Указанный ключ слишком длинный; максимальная длина ключа - 1000 байт
Я знаю, что вопросы с этим заголовком были получены раньше, но, пожалуйста, продолжайте читать. Я прочитал все остальные вопросы/ответы об этой ошибке перед публикацией.
Я получаю вышеуказанную ошибку для следующего запроса:
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;
Кто-нибудь знает, почему и как его исправить?
Ловушка - этот же запрос отлично работает на моей локальной машине, а также работал на моем предыдущем хосте. Btw.it от зрелого проекта - phpdevshell - так что я думаю, эти ребята знают, что они делают, хотя вы никогда не знаете.
Любая подсказка оценена.
Я использую phpMyAdmin.
Ответы
Ответ 1
Как говорит @Devart, общая длина вашего индекса слишком длинная.
Короткий ответ заключается в том, что вы не должны индексировать такие длинные столбцы VARCHAR, так как индекс будет очень громоздким и неэффективным.
Лучшей практикой является использование префиксных индексов, поэтому вы только индексируете левую подстроку данных. Большинство ваших данных будут в любом случае короче 255 символов.
Вы можете объявить длину префикса для каждого столбца при определении индекса. Например:
...
KEY `index` (`parent_menu_id`,`menu_link`(50),`plugin`(50),`alias`(50))
...
Но какая лучшая длина префикса для данного столбца? Здесь можно найти способ:
SELECT
ROUND(SUM(LENGTH(`menu_link`)<10)*100/COUNT(*),2) AS pct_length_10,
ROUND(SUM(LENGTH(`menu_link`)<20)*100/COUNT(*),2) AS pct_length_20,
ROUND(SUM(LENGTH(`menu_link`)<50)*100/COUNT(*),2) AS pct_length_50,
ROUND(SUM(LENGTH(`menu_link`)<100)*100/COUNT(*),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
.
Ответ 2
Эта ошибка означает, что длина индекса index
составляет более 1000 байт. У MySQL и систем хранения есть это ограничение. У меня есть аналогичная ошибка в MySQL 5.5 - "Указанный ключ был слишком длинным; максимальная длина ключа составляет 3072 байта при запуске этого script:
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 байт.
Ответ 3
запустите этот запрос перед созданием или изменением таблицы.
SET @@global.innodb_large_prefix = 1;
это установит максимальную длину ключа в 3072 байта.
Ответ 4
Это ограничение размера индекса, по-видимому, больше в 64-битных сборках MySQL.
Я использовал это ограничение, пытаясь сбросить нашу базу данных dev и загрузить его на локальном VMWare virt. Наконец, я понял, что сервер удаленных разработчиков был 64 бит, и я создал 32-битный virt. Я просто создал 64-битный virt, и мне удалось загрузить базу данных локально.
Ответ 5
Я только что обошел эту ошибку, просто изменив значения "длины" в исходной базе данных на общую сумму около "1000", изменив ее структуру и затем экспортируя ее на сервер.:)