1.發現問題
今天在修改innodb表的某個列的長度時,報如下錯誤:
- alter table test2 modify column id varchar(500);
- ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes
alter table test2 modify column id varchar(500); ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes
2.分析問題
2.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)
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操作可以正常執行
2.2 關於mysql索引長度限制
1)單列索引長度限制
- From the manual at http://dev.mysql.com/doc/refman/5.6/en/create-table.html >>從5.6的官方文檔中我們能找到如下雙引號中解釋
- "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個字符
From the manual at http://dev.mysql.com/doc/refman/5.6/en/create-table.html >>從5.6的官方文檔中我們能找到如下雙引號中解釋 "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
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時,會報錯。
從上面可以看出,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(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)
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(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)
對於myisam存儲引擎,多列索引長度限制如下:
每個列的長度不能大於1000 bytes,所有組成索引列的長度和不能大於1000 bytes
例子如下
- mysql> create table test3(id varchar(334),key(id)) engine=myisam; >>索引列長度大於1000 bytes (334*3=1002),建表報錯
- ERROR 1071 (42000): Specified key was too long; max key length is 1000 bytes
- mysql> create table test3(id varchar(333),key(id)) engine=myisam; >>索引列長度小於1000 bytes (333*3=999),建表成功
- Query OK, 0 rows affected (0.07 sec)
- mysql> create table test3(id varchar(300),name varchar(34),key(id,name)) engine=myisam; >>多列索引,所有列長度大於1000 bytes 建表報錯
- ERROR 1071 (42000): Specified key was too long; max key length is 1000 bytes
- mysql>
mysql> create table test3(id varchar(334),key(id)) engine=myisam; >>索引列長度大於1000 bytes (334*3=1002),建表報錯 ERROR 1071 (42000): Specified key was too long; max key length is 1000 bytes mysql> create table test3(id varchar(333),key(id)) engine=myisam; >>索引列長度小於1000 bytes (333*3=999),建表成功 Query OK, 0 rows affected (0.07 sec) mysql> create table test3(id varchar(300),name varchar(34),key(id,name)) engine=myisam; >>多列索引,所有列長度大於1000 bytes 建表報錯 ERROR 1071 (42000): Specified key was too long; max key length is 1000 bytes mysql>
3. 問題解決方案
1) using col_name(length) syntax to specify an index prefix length.
對列的前面某部分創建索引
2) 啟用innodb_large_prefix參數
- innodb_large_prefix >>啟用innodb_large_prefix參數能夠取消對於索引中每列長度的限制(但是無法取消對於索引總長度的限制)
- 啟用innodb_large_prefix有如下前提條件:
- 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中row_format默認值為compact)
- 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.
innodb_large_prefix >>啟用innodb_large_prefix參數能夠取消對於索引中每列長度的限制(但是無法取消對於索引總長度的限制) 啟用innodb_large_prefix有如下前提條件: 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中row_format默認值為compact) 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.
例子如下:
- 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;
- Query OK, 0 rows affected (0.00 sec)
- mysql> set global innodb_file_format=BARRACUDA;
- Query OK, 0 rows affected (0.00 sec)
- 4. 對row_format為dynamic格式表創建索引測試
- mysql> create table test3(id varchar(256),key (id)) row_format=dynamic;
- Query OK, 0 rows affected (0.14 sec)
- 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的限制仍然存在
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; Query OK, 0 rows affected (0.00 sec) mysql> set global innodb_file_format=BARRACUDA; Query OK, 0 rows affected (0.00 sec) 4. 對row_format為dynamic格式表創建索引測試 mysql> create table test3(id varchar(256),key (id)) row_format=dynamic; Query OK, 0 rows affected (0.14 sec) 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的限制仍然存在