今天在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

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

1: 系统变量innodb_large_prefix为ON

2: 系统变量innodb_file_format为Barracuda

3: 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字节呢? 这样限制又是出于什么具体性能的考虑呢? 暂时还没有弄清楚这些细节问题!

参考资料:

https://dev.mysql.com/doc/refman/5.6/en/innodb-restrictions.html

https://dev.mysql.com/doc/refman/5.7/en/innodb-restrictions.html

ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes的更多相关文章

  1. 索引长度过长 ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes

    1.发现问题 今天在修改innodb表的某个列的长度时,报如下错误: alter table test2 modify column id varchar(500); ERROR 1071 (4200 ...

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

    这个错误是我在安装ambari平台时,准备为ambari指定mysql数据库时,执行建表语句时遇到的. ERROR 1071 (42000): Specified key was too long; ...

  3. 【laravel5.6】 Illuminate\Database\QueryException : SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 1000 bytes

    在进行数据迁移时候报错: 特殊字段太长报错, php artisan migrate 现在utf8mb4包括存储emojis支持.如果你运行MySQL v5.7.7或者更高版本,则不需要做任何事情. ...

  4. Using innodb_large_prefix to avoid ERROR #1071,Specified key was too long; max key length is 1000 bytes

    Using innodb_large_prefix to avoid ERROR 1071        单列索引限制上面有提到单列索引限制767,起因是256×3-1.这个3是字符最大占用空间(ut ...

  5. laravel migrate时报错:Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes

    今天在学习laravel的路由模型绑定时,在按照文档执行php artisan migrate时报错. In Connection.php line 664: SQLSTATE[42000]: Syn ...

  6. laravel错误1071 Specified key was too long; max key length is 1000 bytes

    Laravel 5.5 环境,php artisan migrate 之后,出现错误如题. 检查了一下,代码是这样的: $table->increments('id'); $table-> ...

  7. 导入sql文件报错:1071 Specified key was too long; max key length is 767 bytes

    ref: https://stackoverflow.com/questions/1814532/1071-specified-key-was-too-long-max-key-length-is-7 ...

  8. OpenStack安装keyston 错误BError: (pymysql.err.InternalError) (1071, u‘Specified key was too long; max key length is 767 bytes‘) [SQL: u‘\nCREATE TABLE migrate_ver

    折腾了两天的错误,BError: (pymysql.err.InternalError) (1071, u‘Specified key was too long; max key length is ...

  9. flask建表遇到的错误: flask,sqlalchemy.exc.OperationalError: (MySQLdb._exceptions.OperationalError) (1071, 'Specified key was too long; max key length is 767 bytes')

    error:flask,sqlalchemy.exc.OperationalError: (MySQLdb._exceptions.OperationalError) (1071, 'Specifie ...

随机推荐

  1. [Swift]LeetCode523. 连续的子数组和 | Continuous Subarray Sum

    Given a list of non-negative numbers and a target integer k, write a function to check if the array ...

  2. [Swift]LeetCode1022. 从根到叶的二进制数之和 | Sum of Root To Leaf Binary Numbers

    Given a binary tree, each node has value 0 or 1.  Each root-to-leaf path represents a binary number ...

  3. Visual Studio 2017 怎么将自动生成属性设置为旧版格式

    工具:Visual Studio 2017 1.点击工具,进入选项 2.选项窗口左侧找到C#--代码样式,点击 3.找到表达式首选项中:使用属性的表达式主体.使用索引器的表达式主体和使用访问器的表达式 ...

  4. Java9发布回顾Java 8的十大新特性

    java9已经在北京时间9月22日正式发布,开发者可以在oracle jdk官网上下载到最新的jdk9. 今天,我们先来一起复习一下2014年发布的Java 8的十大新特性.先来喝杯java~~~ 按 ...

  5. 【实战分享】又拍云 OpenResty / Nginx 服务优化实践

    2018 年 11 月 17 日,由 OpenResty 主办的 OpenResty Con 2018 在杭州举行.本次 OpenResty Con 的主题涉及 OpenResty 的新开源特性.业界 ...

  6. 轮询、长轮询与Web Socket的前端实现

    Web Socket 应用场景:实现即时通讯:如股票交易行情分析.聊天室.在线游戏等,替代轮询和长轮询 轮询 轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP request,然后由 ...

  7. slice全解析

    slice全解析 昨天组内小伙伴做分享,给出了这么一段代码: package main import ( "fmt" ) func fun1(x int) { x = x + 1 ...

  8. 从零打卡leetcode之day 1--两数之和

    前言 就是要把leetcode的题刷完,每天一道题,每天进步一点点 从零打卡leetcode之day 1 题目描述: 给定一个整数数组和一个目标值,找出数组中和为目标值的两个数. 你可以假设每个输入只 ...

  9. Vim实现分屏

    主要是sp(seismic profile)和vsp(vertical seismic profile)两个命令, 水平拆分 将vm切换到命令模式,  :sp       实现水平拆分屏幕 垂直拆分 ...

  10. kubernetes系列06—kubernetes资源清单定义入门

    本文收录在容器技术学习系列文章总目录 1.认识kubernetes资源 1.1 常用资源/对象 workload工作负载型资源:pod,ReplicaSet,Deployment,StatefulSe ...