#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 – 所以我想这些人知道他们在做什么,尽pipe你永远不知道。

任何线索赞赏。

我正在使用phpMyAdmin。

正如@Devart所说,你的索引的总长度太长了。

简单的回答是,您不应该索引这么长的VARCHAR列,因为这个索引会非常庞大​​而且效率低下。

最好的做法是使用前缀索引,因此您只需索引数据的左侧子string。 无论如何,你的大部分数据比255个字符要短很多。

您可以在定义索引时为每列声明一个前缀长度。 例如:

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

但是给定列的最佳前缀长度是多less? 这里有一个方法来找出:

 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列中不超过给定string长度的行的比例。 你可能会看到这样的输出:

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

这告诉你80%的stringless于20个字符,并且你所有的stringless于50个字符。 所以不需要索引超过50的前缀长度,当然也不需要索引全长的255个字符。

PS: INT(1)INT(32)数据types表示对MySQL的另一个误解。 数字参数与存储或列允许的值范围无关。 INT始终是4个字节,并且始终允许从-2147483648到2147483647之间的值。数字参数是关于显示过程中的填充值,除非使用ZEROFILL选项,否则不起作用。

这个错误意味着索引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字节。

在创build或更改表之前运行此查询。

SET @@global.innodb_large_prefix = 1;

这会将最大密钥长度设置为3072字节

在64位版本的MySQL中,这个索引大小限制似乎更大。

我碰到这个限制试图转储我们的开发数据库,​​并将其加载到本地VMWare虚拟机。 最后我意识到,远程开发服务器是64位,我创造了一个32位的德尔。 我刚刚创build了一个64位的virt,我能够在本地加载数据库。

我刚刚通过改变原来的数据库中的“长度”的值,通过改变其结构,然后导出到服务器,绕过这个错误绕过“1000”。 🙂