#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”。 🙂