#1071 - 指定密钥太长;最大密钥长度为1000字节

时间:2012-01-05 16:42:09

标签: mysql phpmyadmin mysqldump

我知道此标题的问题之前已经得到解答,但请继续阅读。在发布之前,我已经仔细阅读了有关此错误的所有其他问题/答案。

我收到以下查询的上述错误:

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。

8 个答案:

答案 0 :(得分:129)

正如@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的另一种误解。 numeric参数与存储或列允许的值范围无关。 INT始终为4个字节,它始终允许从-2147483648到2147483647的值。数值参数是关于显示期间的填充值,除非您使用ZEROFILL选项,否则无效。

答案 1 :(得分:25)

此错误表示索引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字节。

答案 2 :(得分:9)

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

SET @@global.innodb_large_prefix = 1;

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

答案 3 :(得分:6)

我有这个问题,并通过以下方式解决:

  

<强>原因

     

MySQL存在一个与MyISAM相关的已知错误,即UTF8字符   您可以在这里查看设置和索引。

     

解决

     
      
  • 确保使用InnoDB存储引擎配置MySQL。

  •   
  • 更改默认使用的存储引擎,以便始终正确创建新表:

         

    set GLOBAL storage_engine='InnoDb';

  •   
  • 对于MySQL 5.6及更高版本,请使用以下命令:

         

    SET GLOBAL default_storage_engine = 'InnoDB';

  •   
  • 最后确保您遵循Migrating to MySQL中提供的说明。

  •   

Reference

答案 4 :(得分:3)

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

我试图转储我们的dev数据库并将其加载到本地VMWare virt上时遇到了这个限制。最后我意识到远程开发服务器是64位,我创建了一个32位的virt。我刚刚创建了一个64位的virt,我能够在本地加载数据库。

答案 5 :(得分:2)

我刚刚通过改变&#34;长度&#34;的值来绕过这个错误。在原始数据库中总共约为&#34; 1000&#34;通过更改其结构,然后将其导出到服务器。 :)

答案 6 :(得分:0)

我也遇到了同样的问题,可通过以下查询来解决。

在创建数据库时,您可以使用utf-8编码

例如create database my_db character set utf8 collate utf8_bin;

答案 7 :(得分:0)

我遇到了这个错误,我将索引外键列的表列长度更改为更小,因此我将其更改如下:

VARCHAR(1024)

致:

VARCHAR(512)

然后再次运行查询。