索引長度過長 ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes


1.發現問題

  今天在修改innodb表的某個列的長度時,報如下錯誤:

 

[html] view plain copy
 
print ?
  1. alter table test2 modify column id varchar(500);  
  2. 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列是否有索引:

 

[html] view plain copy
 
print ?
  1. mysql> show index from test2\G;  
  2. *************************** 1. row ***************************  
  3.         Table: test2  
  4.    Non_unique: 1  
  5.      Key_name: id  
  6.  Seq_in_index: 1  
  7.   Column_name: id  
  8.     Collation: A  
  9.   Cardinality: 0  
  10.      Sub_part: NULL  
  11.        Packed: NULL  
  12.          Null: YES  
  13.    Index_type: BTREE  
  14.       Comment:   
  15. Index_comment:   
  16. 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)單列索引長度限制

 

[html] view plain copy
 
print ?
  1. From the manual at http://dev.mysql.com/doc/refman/5.6/en/create-table.html >>從5.6的官方文檔中我們能找到如下雙引號中解釋  
  2. "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.  
  3. ...  
  4. 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,但是建表時我們指定的長度單位是字符。  
  5.   
  6. 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個字符
[html] view plain copy
 
print ?
  1. create table test2(id varchar(256),primary key(id));  
  2. 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)

 

[html] view plain copy
 
print ?
  1. mysql> create table test3(id varchar(255),key(id));  
  2. Query OK, 0 rows affected (0.11 sec)  >>索引列長度小於767(255*3=765),表創建成功  
  3.   
  4. mysql> drop table test3;  
  5. Query OK, 0 rows affected (0.03 sec)  
  6.   
  7. mysql> create table test3(id varchar(256),key(id));  >>索引列長度大於767(256*3=768),所以創建表失敗  
  8. ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes  
  9. 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),所以表創建失敗  
  10. ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes  
  11. 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));  >>  
  12. 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

例子如下

 

[html] view plain copy
 
print ?
  1. mysql> create table test3(id varchar(334),key(id)) engine=myisam>>索引列長度大於1000 bytes (334*3=1002),建表報錯  
  2. ERROR 1071 (42000): Specified key was too long; max key length is 1000 bytes  
  3. mysql> create table test3(id varchar(333),key(id)) engine=myisam;  >>索引列長度小於1000 bytes (333*3=999),建表成功  
  4. Query OK, 0 rows affected (0.07 sec)  
  5.   
  6. mysql> create table test3(id varchar(300),name varchar(34),key(id,name)) engine=myisam>>多列索引,所有列長度大於1000 bytes 建表報錯  
  7. ERROR 1071 (42000): Specified key was too long; max key length is 1000 bytes  
  8. 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參數

 

[html] view plain copy
 
print ?
  1. innodb_large_prefix >>啟用innodb_large_prefix參數能夠取消對於索引中每列長度的限制(但是無法取消對於索引總長度的限制)  
  2. 啟用innodb_large_prefix有如下前提條件:  
  3. 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=barracudainnodb_file_per_table=true,並且建表的時候指定表的row_format為dynamic或者compressed(mysql 5.6中row_format默認值為compact)  
  4. See Section 14.6.7, “Limits on InnoDB Tables” for the relevant maximums associated with index key prefixes under various settings. >>  
  5. 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.

例子如下:

 

[html] view plain copy
 
print ?
  1. 1. 查看innodb_large_prefix,innodb_file_format參數  
  2. mysql> show variables like 'innodb_large_prefix';  
  3. +---------------------+-------+  
  4. | Variable_name       | Value |  
  5. +---------------------+-------+  
  6. | innodb_large_prefix | OFF   |  
  7. +---------------------+-------+  
  8. 1 row in set (0.01 sec)  
  9.   
  10. mysql> show variables like 'innodb_file_format';  
  11. +--------------------+----------+  
  12. | Variable_name      | Value    |  
  13. +--------------------+----------+  
  14. | innodb_file_format | Antelope |  
  15. +--------------------+----------+  
  16. 1 row in set (0.00 sec)  
  17.   
  18. 2. 建索引測試(innodb_large_prefix,innodb_file_format都為默認值的情況下)  
  19. mysql> create table test3(id varchar(256),key (id));    
  20. ERROR 1709 (HY000): Index column size too large. The maximum column size is 767 bytes.  
  21.   
  22. 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));  
  23. ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes  
  24. ##索引列大於767 bytes時報錯,組合索引列的總長度大於3072 bytes時報錯  
  25.   
  26. 3. 修改innodb_large_prefix,innodb_file_format參數  
  27. mysql> set global innodb_large_prefix=1;  
  28. Query OK, 0 rows affected (0.00 sec)  
  29. mysql> set global innodb_file_format=BARRACUDA;  
  30. Query OK, 0 rows affected (0.00 sec)  
  31.   
  32. 4. 對row_format為dynamic格式表創建索引測試  
  33. mysql> create table test3(id varchar(256),key (id)) row_format=dynamic;  
  34. Query OK, 0 rows affected (0.14 sec)    
  35.   
  36. 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;   
  37. ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes  
  38. ##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的限制仍然存在


 

 



 

 



 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM