错误:
1071 - 指定的密钥太长;最大密钥长度为1000字节
CREATE TABLE `phppos_modules_actions` (
`action_id` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL ,
`module_id` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL ,
`action_name_key` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL ,
`sort` INT NOT NULL ,
PRIMARY KEY ( `action_id` , `module_id` )
) ENGINE = INNODB CHARACTER SET utf8 COLLATE utf8_unicode_ci;
我知道错误的发生是因为255x2x3(每个字符3个字节)
所有安装都不会发生这种情况。我可以更改什么设置?
答案 0 :(得分:11)
根据MySql文档(参见https://dev.mysql.com/doc/refman/5.6/en/sql-mode.html#sqlmode_no_engine_substitution),这是sqlmode NO_ENGINE_SUBSTITUTION的含义:
当a时控制默认存储引擎的自动替换 诸如CREATE TABLE或ALTER TABLE之类的语句指定存储 已禁用或未编译的引擎。
因为存储引擎在运行时可以插入,所以不可用 引擎的处理方式相同:
禁用NO_ENGINE_SUBSTITUTION后,对于CREATE TABLE,默认值为 使用发动机,如果需要发动机,则发出警告 不可用。对于ALTER TABLE,会发生警告而表格不会发生 改变。
启用NO_ENGINE_SUBSTITUTION后,会发生错误,表格为 如果所需的引擎不可用,则不会创建或更改。
MySql版本5.1.56社区
Options in my.cnf
sql-mode=""
default-storage-engine=MYISAM
skip-innodb uncommented (without#)
Return on execution of your create statement:
Error Code: 1071. Specified key was too long; max key length is 1000 bytes
Explanation: INNODB is not active, the engine is automatically switched to MYISAM
that returns this error as they key is longer than MYISAM 1000 bytes limit.
The key length is:
2 fields x 255 char x 3 bytes utf8 encoding + 2 x 1 length byte = 1532 bytes
Options in my.cnf
sql-mode="NO_ENGINE_SUBSTITUTION"
default-storage-engine=MYISAM
skip-innodb uncommented (without#)
Return on execution of your create statement:
Error Code: 1286. Unknown table engine 'INNODB'
Explanation: INNODB is not active but the engine substitution is not permitted
by sql mode therefore the DB returns an error about the attempt of using a disabled engine.
Options in my.cnf
sql-mode="NO_ENGINE_SUBSTITUTION"
default-storage-engine=MYISAM
skip-innodb commented (with#)
Return on execution of your create statement:
Table creation OK!
Explanation: INNODB is active (skip-innodb commented) and it is used also if
the default engine is MYISAM.
要重现测试,请在my.cnf中每次更改后重新启动MySql。
由于默认情况下MySql 5.6版sqlmode不再为空且包含NO_ENGINE_SUBSTITUTION,而且INNODB是默认引擎,因此很难满足错误。
没有其他方法可以重现错误:
Error Code: 1071. Specified key was too long; max key length is 1000 bytes
在尝试创建INNODB表时已找到。
在INNODB中,您有两种ERROR 1071:
Error Code: 1071. Specified key was too long; max key length is 767 bytes
这与innodb_large_prefix ON或OFF无关,但仅与用作索引的单个VARCHAR列的大小有关。
Mysql存储varchar utf8,包含3个字节加1个字节,长度为255个字符,之后为2个字符(请参阅:http://dev.mysql.com/doc/refman/5.7/en/storage-requirements.html),因此如果您尝试使用VARCHAR(256)utf8设置密钥,则会得到:< / p>
256 x 3 + 2 = 770 bytes
并且您得到上一个错误,因为InnoDB表的单个列的最大密钥长度为767个字节。 VARCHAR(255)没问题,因为:
255 x 3 + 1 = 766 bytes
我在四个安装的Mysql,版本5.1.56,5.5.33,5.6和5.7上进行了测试,并且已经确认。您的查询与VARCHAR(255)没有问题,VARCHAR(256)问题:
Error Code: 1071. Specified key was too long; max key length is 767 bytes
正如您所看到的消息不同,因为它是INNODB消息而不是MYISAM消息!
INNODB表的另一种ERROR 1071是:
Error Code: 1071. Specified key was too long; max key length is 3072 bytes
这与具有多列的键有关。要启用这些键,您需要将innodb_large_prefix设置为on。 无论如何,如果你试图运行这样的东西:
CREATE TABLE `phppos_modules_actions` (
`action_id` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL ,
`module_id` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL ,
`action_name_key` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL ,
`action_name_key1` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL ,
`action_name_key2` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL ,
`sort` INT NOT NULL ,
PRIMARY KEY ( `action_id` , `module_id`, `action_name_key`, `action_name_key1`, `action_name_key2` )
) ENGINE = INNODB CHARACTER SET utf8 COLLATE utf8_unicode_ci;
使用5个VARCHAR(255)utf8列的密钥,即3830字节,您将遇到:
Error Code: 1071. Specified key was too long; max key length is 3072 bytes
在寻找原因的过程中,我制定并测试了不同且非常奇怪的假设:
经过测试的REDUNDANT,COMPACT,COMPRESS,DYNAMIC:对您的陈述创建表格没有影响。
经过测试的Antelope和Barracuda:使用您的陈述对表创建没有影响。
经过测试的32位和64位MySql:使用您的语句对表创建没有影响。
在这里,您可以在相同的情况下找到相同的错误:
https://www.drupal.org/node/2466287
我在PROOF中列出的3个测试情况中测试了该声明,并且它再现了与您完全相同的行为,因此我可以说问题是相同的。在这种情况下,他们切换到其他数据库,但问题是设置的混合,而不是数据库版本。
这里给出了一篇非常好的与INNODB建立索引的文章:
http://mechanics.flite.com/blog/2014/07/29/using-innodb-large-prefix-to-avoid-error-1071/
警告:在创建索引超过1000的INNODB表后,通过在my.cnf中取消注释skip-innodb来禁用INNODB将不允许启动MySql服务
此致
答案 1 :(得分:3)
我现在没有多大的灵活性,但这里有一些选择:
将MySQL版本升级到最新版本(我测试了代码 MySQL 5.5.25并没有错误。)
从utf8更改为latin1。
减小构成主键的字段的大小。
创建单独的auto_increment主键字段以替换现有键。在第一个字段action_id
(但不是第二个字段)
除了这些选项之外,你几乎陷入困境,因为在MySQL中没有可以更改的设置可以使索引键大于1000字节。
答案 2 :(得分:3)
在MySQL 5.6.3+中有一些限制(需要ROW_FORMAT=DYNAMIC
,innodb_file_format=BARRACUDA
和innodb_file_per_table=true
),您可以启用innodb_large_prefix
以获得3072字节的密钥长度限制。
答案 3 :(得分:2)
你(意外?)InnoDB关闭了。它将表创建为MyISAM,整个键超过1000个字节。
检查是否有InnoDB的变量,以及是否有&#34; no_engine_substitution&#34; (如果存在于5.1.56中),请检查mysqld.err
以确定它在启动时是否存在一些相关错误。
答案 4 :(得分:1)
它似乎与存储引擎有关。我的最终用户正在使用MyISAM
来处理数据存储,导致错误。
答案 5 :(得分:1)
如上所述,索引的总长度太长。
简短的回答是,你不应该为这样长的VARCHAR
列编制索引,因为索引会非常庞大且效率低下。
最佳做法是使用前缀索引,这样您只需索引数据的左子字符串。无论如何,你的大多数数据都会短于255个字符。
767字节是InnoDB
表的规定前缀限制 - MyISAM
表的长度为1,000字节。
根据对此问题的回复,您可以通过指定列的子集而不是整个数量来获取要应用的密钥。意味着您可以在定义索引时声明每列的前缀长度。
例如:
KEY `key_name` (`action_id`(50),`module_id`(50))
以下是更清楚地解释它的示例:我创建了一个表并在其中插入了一些数据。
CREATE TABLE `phppos_modules_actions` (
`action_id` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL ,
`module_id` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL ,
`action_name_key` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL ,
`sort` INT NOT NULL ,
PRIMARY KEY ( `action_id`(50) , `module_id`(50) )
) ENGINE = INNODB CHARACTER SET utf8 COLLATE utf8_unicode_ci;
但是给定列的最佳前缀长度是多少?这是一个找出方法:
SELECT
ROUND(SUM(LENGTH(`action_id`)<10)*100/COUNT(*),2) AS pct_length_10,
ROUND(SUM(LENGTH(`action_id`)<20)*100/COUNT(*),2) AS pct_length_20,
ROUND(SUM(LENGTH(`action_id`)<50)*100/COUNT(*),2) AS pct_length_50,
ROUND(SUM(LENGTH(`action_id`)<100)*100/COUNT(*),2) AS pct_length_100
FROM `phppos_modules_actions`;
+---------------+---------------+---------------+----------------+
| pct_length_10 | pct_length_20 | pct_length_50 | pct_length_100 |
+---------------+---------------+---------------+----------------+
| 42.86 | 80.20 | 100 | 100 |
+---------------+---------------+---------------+----------------+
这告诉您80%的字符串少于20个字符,并且所有字符串都少于50个字符。因此,不需要索引超过50的前缀长度,当然也不需要索引255个字符的全长。
调整,因为你需要获取密钥才能应用,但我想知道是否值得查看有关此实体的数据模型,看看是否有改进可以让你实现预期的业务规则而不需要MySQL限制。
关于innodb中设置的一些替代方法可以在http://mechanics.flite.com/blog/2014/07/29/using-innodb-large-prefix-to-avoid-error-1071/
找到答案 6 :(得分:0)
限制 InnoDB 表
InnoDB内部最大密钥长度为3500字节,但MySQL本身 将此限制为3072字节。此限制适用于 多列索引中的组合索引键。
http://dev.mysql.com/doc/refman/5.7/en/innodb-restrictions.html
MyISAM 存储引擎
最大密钥长度为1000个字节。这也可以改变 更改源和重新编译。对于密钥长于的情况 250字节,一个比默认值1024字节更大的密钥块大小 使用
http://dev.mysql.com/doc/refman/5.7/en/myisam-storage-engine.html
但是你的表被声明为InnoDB。所以我不知道该怎么想
这个old bug
结尾处还有一条线索如果你需要这个,你应该看看MySQL 5.5以及从5.5.14(2011年7月)开始提供的innodb_large_prefix选项,因为它可能正在寻找你想要的东西:
“启用此选项以允许索引键前缀长于767字节 (最多3072字节),用于使用DYNAMIC和的InnoDB表 压缩行格式。 (创建这样的表也需要 选项值innodb_file_format = barracuda和 innodb_file_per_table = true。)请参见第13.3.15节“InnoDB的限制 “表”用于与索引键前缀关联的相关最大值 在各种环境下。
答案 7 :(得分:0)
最大密钥长度为1000个字节。这也可以通过更改源和重新编译来更改。对于长度大于250字节的密钥的情况,使用比默认值1024字节更大的密钥块大小。
答案 8 :(得分:0)
就我而言,MySQL是在没有InnoDB支持的情况下启动的。在数据库备份导入期间 - 尝试创建MyISAM表。
同时,MySQL重启期间控制台中没有显示任何错误 只有在检查MySQL日志文件时 - 才能找到它。
BTW错误与innodb_log_file_size = 4G
有关,只有在将其更改为innodb_log_file_size = 1G
时才会启用 - 启用了InnoDB支持。