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

1.版本

1)操作系统

 cat /etc/issue
cat /etc/issue
CentOS release 6.6 (Final)
Kernel \r on an \m

 cat /proc/version
cat /proc/version
Linux version 2.6.32-504.el6.x86_64 (mockbuild@c6b9.bsys.dev.centos.org) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-11) (GCC) ) #1 SMP Wed Oct 15 04:27:16 UTC 2014

2)mysql数据库版本

mysql --version
mysql  Ver 14.14 Distrib 5.6.26, for linux-glibc2.5 (x86_64) using  EditLine wrapper

2.问题描述

2.1 发现问题

  今天在修改innodb表的某个列的长度时,报如下错误:

alter table test2 modify column id varchar(500);
ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes


3.分析问题

3.1 问题原因分析

其实从上面的报错中我们已经能看是因为索引达到长度限制,所以报错。查看id列是否有索引:

mysql> show index from test2\G;
*************************** 1. row ***************************
        Table: test2
   Non_unique: 1
     Key_name: id
 Seq_in_index: 1
  Column_name: id
    Collation: A
  Cardinality: 0
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment: 
Index_comment: 
1 row in set (0.00 sec)

##删除id列的索引后, alter table test2 modify操作可以正常执行

3.2 关于mysql索引长度限制

1)单列索引长度限制

##5.6的官方文档中我们能找到如下双引号中解释
From the manual at http://dev.mysql.com/doc/refman/5.6/en/create-table.html 
"For CHAR, VARCHAR, BINARY, and VARBINARY columns, 
indexes can be created that use only the leading part of column values,
 using col_name(length) syntax to specify an index prefix length.
...
Prefixes can be up to 1000 bytes long (767 bytes for InnoDB tables). 
Note that prefix limits are measured in bytes, 
whereas the prefix length in CREATE TABLE statements is interpreted as number of characters ..."
>>>对于myisam和innodb存储引擎,prefixes的长度限制分别为1000 bytes和767 bytes。
注意prefix的单位是bytes,但是建表时我们指定的长度单位是字符。

A utf8 character can use up to 3 bytes. Hence you cannot 
index columns or prefixes of columns longer than 
333 (MyISAM) or 255 (InnoDB) utf8 characters.  
>>>>以utf8字符集为例,一个字符占3个bytes。因此在utf8字符集下,
对myisam和innodb存储引擎创建索引的单列长度不能超过333个字符和255个字符
create table test2(id varchar(256),primary key(id));
ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes

##对于innodb表,索引列长度大于255时,会报错。

 create table test2(id varchar(334),primary key(id)) engine=myisam default character set utf8;
ERROR 1071 (42000): Specified key was too long; max key length is 1000 bytes
>>默认情况下myisam 表单列索引长度不能超过 1000 bytes

  从上面可以看出,mysql 在创建单列索引的时候对列的长度是有限制的 myisam和innodb存储引擎下长度限制分别为1000 bytes和767 bytes。(注意bytes和character的区别)

2) 组合索引长度限制

  对于innodb存储引擎,多列索引的长度限制如下:

每个列的长度不能大于767 bytes;所有组成索引列的长度和不能大于3072 bytes

参考如下例子(下面默认使用的使用innodb存储引擎,smallint 占2个bytes,timestamp占4个bytes,utf8字符集。utf8字符集下,一个character占三个byte)

mysql> create table test3(id varchar(255),key(id));
Query OK, 0 rows affected (0.11 sec)  >>索引列长度小于767(255*3=765),表创建成功

mysql> drop table test3;
Query OK, 0 rows affected (0.03 sec)

mysql> create table test3(id varchar(256),key(id));  >>索引列长度大于767(256*3=768),所以创建表失败
ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes
mysql> create table test3 (id varchar(255),name varchar(255),name1 varchar(255),name2 varchar(255),name3 varchar(5),key (id,name,name1,name2,name3));  
>>innodb下多列索引,所有列长度和大于3072/3=1024 (255*4+5=1025),所以表创建失败
ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes

mysql> create table test3 (id varchar(256),name varchar(255),key (id,name));
ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes
>>创建组合索引时,每个列也不能超过 767 bytes的限制(对于 innodb 来说) 

mysql> create table test3 (id varchar(255),name varchar(255),name1 varchar(255),name2 varchar(255),name3 varchar(4),key (id,name,name1,name2,name3));
Query OK, 0 rows affected (0.09 sec)
>>单列不超过 767 bytes,总长度不超过 3072 bytes索引创建成功

  对于myisam存储引擎,多列索引长度限制如下:

每个列的长度不能大于1000 bytes,所有组成索引列的长度和不能大于1000 bytes

例子如下

mysql> create table test3(id varchar(334),key(id)) engine=myisam; 
ERROR 1071 (42000): Specified key was too long; max key length is 1000 bytes
>>索引列长度大于1000 bytes (334*3=1002),建表报错

mysql> create table test3(id varchar(333),key(id)) engine=myisam;  
Query OK, 0 rows affected (0.07 sec)
>>索引列长度小于1000 bytes (333*3=999),建表成功

mysql> create table test3(id varchar(300),name varchar(34),key(id,name)) engine=myisam; 
ERROR 1071 (42000): Specified key was too long; max key length is 1000 bytes
>>多列索引,所有列长度大于1000 bytes 建表报错

4. 问题解决方案

1) using col_name(length) syntax to specify an index prefix length.(使用前缀索引)

alter table Table_Name add key(column_name(prefix_len));

alter table test_6 add index idx_name(name(100));

create index index_name on Table_Name(column_name(prefix_len));

对列的前面某部分创建索引

2) 启用innodb_large_prefix参数

innodb_large_prefix 5.6该参数默认不启用
>>启用innodb_large_prefix参数把单列索引长度限制提升为3072 bytes(不会影响复合索引长度限制,还为3072 bytes)

Enable this option to allow index key prefixes longer than 767 bytes (up to 3072 bytes)
for InnoDB tables that use the DYNAMIC and COMPRESSED row formats.
(Creating such tables also requires the option values innodb_file_format=barracuda and innodb_file_per_table=true.) 
>>启用innodb_large_prefix并且指定innodb_file_format=barracuda,innodb_file_per_table=true,同时建表的时候指定表的row_format
为dynamic或者compressed(mysql 5.6中默认innodb_file_format=Antelope,默认row_format为Compact)这时就能把该表的单列索引长度限制提升为 3072 bytes
See Section 14.6.7, “Limits on InnoDB Tables” for the relevant maximums associated with index key prefixes under various settings.
For tables using the REDUNDANT and COMPACT row formats, this option does not affect the allowed key prefix length.
>>对于 REDUNDANT 和 COMPACT row_format 的表,即使启用了innodb_large_prefix参数,
其单列索引长度限制依然为 767 bytes

例子如下:

1. 查看innodb_large_prefix,innodb_file_format参数
mysql> show variables like 'innodb_large_prefix';
+---------------------+-------+
| Variable_name       | Value |
+---------------------+-------+
| innodb_large_prefix | OFF   |
+---------------------+-------+
1 row in set (0.01 sec)

mysql> show variables like 'innodb_file_format';
+--------------------+----------+
| Variable_name      | Value    |
+--------------------+----------+
| innodb_file_format | Antelope |
+--------------------+----------+
1 row in set (0.00 sec)

2. 建索引测试(innodb_large_prefix,innodb_file_format都为默认值的情况下)
mysql> create table test3(id varchar(256),key (id));  
ERROR 1709 (HY000): Index column size too large. The maximum column size is 767 bytes.

mysql> create table test3(id varchar(255),name varchar(255),name1 varchar(255),name2 varchar(255),name3 varchar(5),key (id,name,name1,name2,name3));
ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
##索引列大于767 bytes时报错,组合索引列的总长度大于3072 bytes时报错

3. 修改innodb_large_prefix,innodb_file_format参数不变
mysql> set global innodb_large_prefix=1;

mysql> create table test3 (id varchar(256),key (id));
ERROR 1709 (HY000): Index column size too large. The maximum column size is 767 bytes.
>>此时表的单列索引长度限制依然为 767 bytes


4. 修改innodb_large_prefix,innodb_file_format参数
mysql> set global innodb_large_prefix=1;
Query OK, 0 rows affected (0.00 sec)
mysql> set global innodb_file_format=BARRACUDA;
Query OK, 0 rows affected (0.00 sec)

1) 建表时使用默认 row_format
 create table test3 (id varchar(256),key (id));
ERROR 1709 (HY000): Index column size too large. The maximum column size is 767 bytes.
>>此时表的单列索引长度限制依然为 767 bytes

2) 使用 dynamic/compressed row_format格式表创建索引测试
mysql> create table test3(id varchar(256),key (id)) row_format=dynamic;
Query OK, 0 rows affected (0.14 sec) 
mysql> create table test4 (id varchar(256),key (id)) row_format=compressed;
Query OK, 0 rows affected (0.01 sec) 
mysql> create table test5 (id varchar(1024),key (id)) row_format=compressed;
Query OK, 0 rows affected (0.01 sec)
mysql> create table test6 (id varchar(1025),key (id)) row_format=compressed;
ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
>>建表时指定 row_format 为dynamic或者compressed时表单列索引长度限制变成 3072 bytes

3) 组合索引长度限制测试
mysql> create table test3(id varchar(255),name varchar(255),name1 varchar(255),name2 varchar(255),name3 varchar(5),key (id,name,name1,name2,name3)) row_format=dynamic; 
ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
##innodb_large_prefix=1并且innodb_file_format=BARRACUDA时,对于row_format为dynamic的表可以指定索引列长度大于767 bytes。但是索引列总长度的不能大于3072 bytes的限制仍然存在

5.相关知识更新(2022/11/16)

最近发现 5.7 版本中索引长度的限制对比5.6版本中有所变化,一并贴出来:

 MySQL 5.7 版本中单列索引和组合索引的索引长度限制都是 3072 bytes

6.参考阅读

参考阅读:

关于mysql innodb 如何保存大对象(BLOB等),最强解析

Blob Storage in Innodb


 

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

渔夫数据库笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值