MySQL 问题分析:ERROR 1071 : Specified key was too long;max

今天在MySQL 5.6版本的数据库中修改InnoDB表字段长度时遇到了”ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes”错误,第一次遇到这个错误,遂花了点学习、研究过、总结这个问题。

我们先来创建一个测试表,构造这样的错误。

mysql> use MyDB;

Reading table information for completion of table and column names

You can turn off this feature to get a quicker startup with -A

Database changed

mysql> CREATE TABLE TEST (

-> CODE_NAME varchar(100) NOT NULL DEFAULT '',

-> CODE_SEQ smallint(6) NOT NULL DEFAULT '1',

-> ACTIVE char(1) DEFAULT 'Y',

-> CODE_VALUE1 varchar(250) DEFAULT NULL,

-> PRIMARY KEY (CODE_NAME,CODE_SEQ),

-> KEY IDX_GEN_CODE (CODE_NAME,CODE_VALUE1)

-> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Query OK, 0 rows affected (0.02 sec)

mysql> ALTER TABLE TEST MODIFY CODE_VALUE1 VARCHAR(350);

ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes

mysql>

其实这个“ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes”错误是指超出索引字节的限制,并不是指字段长度限制。在官方文档“Limits on InnoDB Tables”有关于这方面的介绍、描述(详情请见参考资料):

MySQL 5.6文档内容如下

By default, the index key prefix length limit is 767 bytes. See Section 13.1.13, “CREATE INDEX Syntax”. For example, you might hit this limit with a column prefix index of more than 255 characters on a TEXT or VARCHAR column, assuming a utf8mb3 character set and the maximum of 3 bytes for each character. When the innodb_large_prefix configuration option is enabled, the index key prefix length limit is raised to 3072 bytes for InnoDB tables that use DYNAMIC or COMPRESSED row format.

Attempting to use an index key prefix length that exceeds the limit returns an error. To avoid such errors in replication configurations, avoid enablinginnodb_large_prefix on the master if it cannot also be enabled on slaves.

The limits that apply to index key prefixes also apply to full-column index keys.

MySQL 5.7文档内容如下:

If innodb_large_prefix is enabled (the default), the index key prefix limit is 3072 bytes for InnoDB tables that use DYNAMIC or COMPRESSED row format. If innodb_large_prefix is disabled, the index key prefix limit is 767 bytes for tables of any row format.

innodb_large_prefix is deprecated and will be removed in a future release. innodb_large_prefix was introduced in MySQL 5.5 to disable large index key prefixes for compatibility with earlier versions of InnoDB that do not support large index key prefixes.

The index key prefix length limit is 767 bytes for InnoDB tables that use the REDUNDANT or COMPACT row format. For example, you might hit this limit with a column prefix index of more than 255 characters on a TEXT or VARCHAR column, assuming a utf8mb3 character set and the maximum of 3 bytes for each character.

Attempting to use an index key prefix length that exceeds the limit returns an error. To avoid such errors in replication configurations, avoid enablinginnodb_large_prefix on the master if it cannot also be enabled on slaves.

The limits that apply to index key prefixes also apply to full-column index keys.

如果启用了系统变量innodb_large_prefix(默认启用,注意实验版本为MySQL 5.6.41,默认是关闭的,MySQL 5.7默认开启),则对于使用DYNAMIC或COMPRESSED行格式的InnoDB表,索引键前缀限制为3072字节。如果禁用innodb_large_prefix,则对于任何行格式的表,索引键前缀限制为767字节。

innodb_large_prefix将在以后的版本中删除、弃用。在MySQL 5.5中引入了innodb_large_prefix,用来禁用大型前缀索引,以便与不支持大索引键前缀的早期版本的InnoDB兼容。

对于使用REDUNDANT或COMPACT行格式的InnoDB表,索引键前缀长度限制为767字节。例如,您可能会在TEXT或VARCHAR列上使用超过255个字符的列前缀索引达到此限制,假设为utf8mb3字符集,并且每个字符最多包含3个字节。

尝试使用超出限制的索引键前缀长度会返回错误。要避免复制配置中出现此类错误,请避免在主服务器上启用enableinnodb_large_prefix(如果无法在从服务器上启用)。

适用于索引键前缀的限制也适用于全列索引键。

注意:上面是767个字节,而不是字符,具体到字符数量,这就跟字符集有关。GBK是双字节的,UTF-8是三字节的

解决方案:

1:启用系统变量innodb_large_prefix

注意:光有这个系统变量开启是不够的。必须满足下面几个条件:

系统变量innodb_large_prefix为ON

系统变量innodb_file_format为Barracuda

ROW_FORMAT为DYNAMIC或COMPRESSED

如下测试所示:

mysql> show variables like '%innodb_large_prefix%';

+---------------------+-------+

| Variable_name | Value |

+---------------------+-------+

| innodb_large_prefix | OFF |

+---------------------+-------+

1 row in set (0.00 sec)

mysql> set global innodb_large_prefix=on;

Query OK, 0 rows affected (0.00 sec)

mysql> ALTER TABLE TEST MODIFY CODE_VALUE1 VARCHAR(350);

ERROR 1709 (HY000): Index column size too large. The maximum column size is 767 bytes.

mysql>

mysql> show variables like '%innodb_file_format%';

+--------------------------+-----------+

| Variable_name | Value |

+--------------------------+-----------+

| innodb_file_format | Antelope |

| innodb_file_format_check | ON |

| innodb_file_format_max | Barracuda |

+--------------------------+-----------+

3 rows in set (0.01 sec)

mysql> set global innodb_file_format=Barracuda;

Query OK, 0 rows affected (0.00 sec)

mysql> ALTER TABLE TEST MODIFY CODE_VALUE1 VARCHAR(350);

ERROR 1709 (HY000): Index column size too large. The maximum column size is 767 bytes.

mysql>

mysql>

mysql> show table status from MyDB where name='TEST'\G;

*************************** 1. row ***************************

Name: TEST

Engine: InnoDB

Version: 10

Row_format: Compact

Rows: 0

Avg_row_length: 0

Data_length: 16384

Max_data_length: 0

Index_length: 16384

Data_free: 0

Auto_increment: NULL

Create_time: 2018-09-20 13:53:49

Update_time: NULL

Check_time: NULL

Collation: utf8_general_ci

Checksum: NULL

Create_options:

Comment:

mysql> ALTER TABLE TEST ROW_FORMAT=DYNAMIC;

Query OK, 0 rows affected (0.05 sec)

Records: 0 Duplicates: 0 Warnings: 0

mysql> show table status from MyDB where name='TEST'\G;

*************************** 1. row ***************************

Name: TEST

Engine: InnoDB

Version: 10

Row_format: Dynamic

Rows: 0

Avg_row_length: 0

Data_length: 16384

Max_data_length: 0

Index_length: 16384

Data_free: 0

Auto_increment: NULL

Create_time: 2018-09-20 14:04:05

Update_time: NULL

Check_time: NULL

Collation: utf8_general_ci

Checksum: NULL

Create_options: row_format=DYNAMIC

Comment:

1 row in set (0.00 sec)

ERROR:

No query specified

mysql> ALTER TABLE TEST MODIFY CODE_VALUE1 VARCHAR(350);

Query OK, 0 rows affected (0.02 sec)

Records: 0 Duplicates: 0 Warnings: 0

2:使用前缀索引解决这个问题

之所以要限制索引键值的大小,是因为性能问题,而前缀索引能很好的解决这个问题。不需要修改任何系统变量。

mysql> show index from TEST;

..................................

mysql> ALTER TABLE TEST DROP INDEX IDX_GEN_CODE;

Query OK, 0 rows affected (0.00 sec)

Records: 0 Duplicates: 0 Warnings: 0

mysql> CREATE IDX_GEN_CODE TEST ON TEST (CODE_NAME, CODE_VALUE1(12));

Query OK, 0 rows affected (0.01 sec)

Records: 0 Duplicates: 0 Warnings: 0

mysql> ALTER TABLE TEST MODIFY CODE_VALUE1 VARCHAR(350);

Query OK, 1064 rows affected (0.08 sec)

Records: 1064 Duplicates: 0 Warnings: 0

问题延伸: 为什么InnoDB的索引字节数限制为767字节? 而不是800字节呢? 这样限制又是出于什么具体性能的考虑呢? 暂时还没有弄清楚这些细节问题!

在这里给大家提供一个学习交流的平台,java架构师群: 867748702

具有1-5工作经验的,面对目前流行的技术不知从何下手,需要突破技术瓶颈的可以加群。

在公司待久了,过得很安逸,但跳槽时面试碰壁。需要在短时间内进修、跳槽拿高薪的可以加群。

如果没有工作经验,但基础非常扎实,对java工作机制,常用设计思想,常用java开发框架掌握熟练的可以加群。

加Java架构师进阶交流群获取Java工程化、高性能及分布式、高性能、深入浅出。高架构。

性能调优、Spring,MyBatis,Netty源码分析和大数据等多个知识点高级进阶干货的直播免费学习权限

都是大牛带飞 让你少走很多的弯路的 群号是: 867748702对了 小白勿进 最好是有开发经验

注:加群要求

1、具有工作经验的,面对目前流行的技术不知从何下手,需要突破技术瓶颈的可以加。

2、在公司待久了,过得很安逸,但跳槽时面试碰壁。需要在短时间内进修、跳槽拿高薪的可以加。

3、如果没有工作经验,但基础非常扎实,对java工作机制,常用设计思想,常用java开发框架掌握熟练的,可以加。

4、觉得自己很牛B,一般需求都能搞定。但是所学的知识点没有系统化,很难在技术领域继续突破的可以加。

5.阿里Java高级大牛直播讲解知识点,分享知识,多年工作经验的梳理和总结,带着大家全面、科学地建立自己的技术体系和技术认知

转载于:https://juejin.im/post/5bd1a850e51d457abf548e98

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值