关于InnoDB索引长度限制的问题
2017-01-23 09:52
429 查看
摘要: 大家经常碰到InnoDB单列索引长度不能超过767bytes,实际上联合索引还有一个限制是3072。
Sql代码 链接地址
mysql> CREATE TABLE `tb` (
-> `a` varchar(255) DEFAULT NULL,
-> `b` varchar(255) DEFAULT NULL,
-> `c` varchar(255) DEFAULT NULL,
-> `d` varchar(255) DEFAULT NULL,
-> `e` varchar(255) DEFAULT NULL,
-> KEY `a` (`a`,`b`,`c`,`d`,`e`)
-> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
可以看到,由于每个字段占用255*3, 因此这个索引的大小是3825>3072,报错。
所以一个记录最多不能超过8k。
又由于InnoDB的聚簇索引结构,一个二级索引要包含主键索引,因此每个单个索引不能超过4k (极端情况,pk和某个二级索引都达到这个限制)。
由于需要预留和辅助空间,扣掉后不能超过3500,取个“整数”就是(1024*3)。
这个参数默认值是OFF。当改为ON时,允许列索引最大达到3072。
如下效果(5.5):
可以看到默认行为是建表成功,报一个warning,并且将长度阶段为255。
注意要生效需要加row_format=compressed或者dynamic 。
MySQL MyIsam 存储引擎在创建索引的时候,索引键长度是有一个较为严格的长度限制的,所有索引键最大长度总和不能超过1000,而且不是实际数据长度的总和,而是索引键字段定义长度的总和。下面做个简单的测试,记录一下。
root@sky:~# mysql -u sky -p -h127.0.0.1
Enter password:
Welcome to the MySQL monitor. Commands end with ; or g.
Your MySQL connection id is 44
Server version: 5.0.51a-log MySQL Community Server (GPL)
Type ‘help;’ or ‘h’ for help. Type ‘c’ to clear the buffer.
sky@127.0.0.1 : (none) 05:23:08> use test;
Database changed
sky@127.0.0.1 : test 05:23:11>
sky@127.0.0.1 : test 05:23:12>
先创建一个MyIsam表,字符集选择latin1,三个字段均设置为varchar 255,:
sky@127.0.0.1 : test 05:23:12> create table test_ind
-> (a varchar(255),
-> b varchar(255),
-> c varchar(255)
-> ) engine=myisam charset=latin1;
Query OK, 0 rows affected (0.01 sec)
创建效果:
sky@127.0.0.1 : test 05:23:32> show create table test_indG
*************************** 1. row ***************************
Table: test_ind
Create Table: CREATE TABLE `test_ind` (
`a` varchar(255) default NULL,
`b` varchar(255) default NULL,
`c` varchar(255) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
三个字段联合索引(长度应该在1000以内)
sky@127.0.0.1 : test 05:23:41> create index test_a_b_c_ind on test_ind(a,b,c);
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
我们看到,创建成功了。
下面我们做一次字符集转换,将字符集转换成utf8
sky@127.0.0.1 : test 05:25:54> alter table test_ind convert to charset utf8;
ERROR 1071 (42000): Specified key was too long; max key length is 1000 bytes
sky@127.0.0.1 : test 05:26:24>
sky@127.0.0.1 : test 05:28:03> show create table test_indG
*************************** 1. row ***************************
Table: test_ind
Create Table: CREATE TABLE `test_ind` (
`a` varchar(255) default NULL,
`b` varchar(255) default NULL,
`c` varchar(255) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
结果报错了,查看表实际情况也确实没有成功,仍然是latin1的字符集。
我们现drop掉索引,再转换字符集。
sky@127.0.0.1 : test 05:28:10> drop index test_a_b_c_ind on test_ind;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
sky@127.0.0.1 : test 05:28:15> alter table test_ind convert to charset utf8;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
sky@127.0.0.1 : test 05:28:20> show create table test_indG
*************************** 1. row ***************************
Table: test_ind
Create Table: CREATE TABLE `test_ind` (
`a` varchar(255) default NULL,
`b` varchar(255) default NULL,
`c` varchar(255) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
转换很顺利,成功了。
现在再创建索引看看效果怎样:
sky@127.0.0.1 : test 05:28:36> create index test_a_b_c_ind on test_ind(a,b,c);
ERROR 1071 (42000): Specified key was too long; max key length is 1000 bytes
失败,减少索引键字段
sky@127.0.0.1 : test 05:28:54> create index test_a_b_c_ind on test_ind(a,b);
ERROR 1071 (42000): Specified key was too long; max key length is 1000 bytes
还是失败,继续减少
sky@127.0.0.1 : test 05:29:00> create index test_a_b_c_ind on test_ind(a);
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
ok,总算成功了。
(row_format=compressed或者dynamic )
若不想重启,可以执行先修改改值,然后在mysql里面执行:set global innodb_large_prefix=on;
生效(该做法重启后失效),因为已经修改了值,所以下次重启也会自动生效的。
关于3072
大家经常碰到InnoDB单列索引长度不能超过767bytes,实际上联合索引还有一个限制是3072。Sql代码 链接地址
mysql> CREATE TABLE `tb` (
-> `a` varchar(255) DEFAULT NULL,
-> `b` varchar(255) DEFAULT NULL,
-> `c` varchar(255) DEFAULT NULL,
-> `d` varchar(255) DEFAULT NULL,
-> `e` varchar(255) DEFAULT NULL,
-> KEY `a` (`a`,`b`,`c`,`d`,`e`)
-> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
可以看到,由于每个字段占用255*3, 因此这个索引的大小是3825>3072,报错。
为什么3072
我们知道InnoDB一个page的默认大小是16k。由于是Btree组织,要求叶子节点上一个page至少要包含两条记录(否则就退化链表了)。所以一个记录最多不能超过8k。
又由于InnoDB的聚簇索引结构,一个二级索引要包含主键索引,因此每个单个索引不能超过4k (极端情况,pk和某个二级索引都达到这个限制)。
由于需要预留和辅助空间,扣掉后不能超过3500,取个“整数”就是(1024*3)。
单列索引限制
上面有提到单列索引限制767,起因是256×3-1。这个3是字符最大占用空间(utf8)。但是在5.5以后,开始支持4个字节的uutf8。255×4>767, 于是增加了一个参数叫做 innodb_large_prefix。这个参数默认值是OFF。当改为ON时,允许列索引最大达到3072。
如下效果(5.5):
可以看到默认行为是建表成功,报一个warning,并且将长度阶段为255。
注意要生效需要加row_format=compressed或者dynamic 。
MySQL MyIsam 存储引擎在创建索引的时候,索引键长度是有一个较为严格的长度限制的,所有索引键最大长度总和不能超过1000,而且不是实际数据长度的总和,而是索引键字段定义长度的总和。下面做个简单的测试,记录一下。
root@sky:~# mysql -u sky -p -h127.0.0.1
Enter password:
Welcome to the MySQL monitor. Commands end with ; or g.
Your MySQL connection id is 44
Server version: 5.0.51a-log MySQL Community Server (GPL)
Type ‘help;’ or ‘h’ for help. Type ‘c’ to clear the buffer.
sky@127.0.0.1 : (none) 05:23:08> use test;
Database changed
sky@127.0.0.1 : test 05:23:11>
sky@127.0.0.1 : test 05:23:12>
先创建一个MyIsam表,字符集选择latin1,三个字段均设置为varchar 255,:
sky@127.0.0.1 : test 05:23:12> create table test_ind
-> (a varchar(255),
-> b varchar(255),
-> c varchar(255)
-> ) engine=myisam charset=latin1;
Query OK, 0 rows affected (0.01 sec)
创建效果:
sky@127.0.0.1 : test 05:23:32> show create table test_indG
*************************** 1. row ***************************
Table: test_ind
Create Table: CREATE TABLE `test_ind` (
`a` varchar(255) default NULL,
`b` varchar(255) default NULL,
`c` varchar(255) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
三个字段联合索引(长度应该在1000以内)
sky@127.0.0.1 : test 05:23:41> create index test_a_b_c_ind on test_ind(a,b,c);
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
我们看到,创建成功了。
下面我们做一次字符集转换,将字符集转换成utf8
sky@127.0.0.1 : test 05:25:54> alter table test_ind convert to charset utf8;
ERROR 1071 (42000): Specified key was too long; max key length is 1000 bytes
sky@127.0.0.1 : test 05:26:24>
sky@127.0.0.1 : test 05:28:03> show create table test_indG
*************************** 1. row ***************************
Table: test_ind
Create Table: CREATE TABLE `test_ind` (
`a` varchar(255) default NULL,
`b` varchar(255) default NULL,
`c` varchar(255) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
结果报错了,查看表实际情况也确实没有成功,仍然是latin1的字符集。
我们现drop掉索引,再转换字符集。
sky@127.0.0.1 : test 05:28:10> drop index test_a_b_c_ind on test_ind;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
sky@127.0.0.1 : test 05:28:15> alter table test_ind convert to charset utf8;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
sky@127.0.0.1 : test 05:28:20> show create table test_indG
*************************** 1. row ***************************
Table: test_ind
Create Table: CREATE TABLE `test_ind` (
`a` varchar(255) default NULL,
`b` varchar(255) default NULL,
`c` varchar(255) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
转换很顺利,成功了。
现在再创建索引看看效果怎样:
sky@127.0.0.1 : test 05:28:36> create index test_a_b_c_ind on test_ind(a,b,c);
ERROR 1071 (42000): Specified key was too long; max key length is 1000 bytes
失败,减少索引键字段
sky@127.0.0.1 : test 05:28:54> create index test_a_b_c_ind on test_ind(a,b);
ERROR 1071 (42000): Specified key was too long; max key length is 1000 bytes
还是失败,继续减少
sky@127.0.0.1 : test 05:29:00> create index test_a_b_c_ind on test_ind(a);
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
ok,总算成功了。
备注总结:
查看状态:
show variables like 'innodb_large_prefix';修改状态:
set global innodb_large_prefix=on;刷新:
FLUSH PRIVILEGES;修改行格式:
ALTER TABLE `tb_table` ROW_FORMAT=Dynamic;(row_format=compressed或者dynamic )
执行创建索引:
ALTER TABLE `tb_table` ADD constraint index_name UNIQUE ( `column` ) ;其他
腾讯云修改innodb_large_prefix为NO时,需要点击修改当前值重启后才能生效。若不想重启,可以执行先修改改值,然后在mysql里面执行:set global innodb_large_prefix=on;
生效(该做法重启后失效),因为已经修改了值,所以下次重启也会自动生效的。
相关文章推荐
- 关于InnoDB索引长度限制的问题
- 关于InnoDB索引长度限制的tips
- 关于InnoDB索引长度限制的tips
- 关于InnoDB索引长度限制的tips
- 关于 InnoDB 索引长度限制的 tips
- 关于MySQL数据库InnoDB存储引擎索引长度限制的tips
- rails mysql2中文编码及innodb前缀索引长度问题
- 关于HTTP的GET请求参数长度限制问题和我对中国式教育的吐槽
- 关于Oracle用sqlldr导入限制值长度大于255问题解决方法
- 关于cmd输入字符长度限制问题
- 关于UDP发包长度及分包问题限制问题(笔记)
- 关于textarea 限制长度 的问题
- 关于Ajax传参长度限制问题(状态:400)
- MySQL索引长度限制问题
- MySQL索引长度限制问题
- js关于字符长度限制的问题示例探讨
- 关于InnoDB的索引大小的问题和注意事项
- 关于Oracle中varchar2和dbms_output.put_line的长度限制问题小结
- js关于字符长度限制的问题示例探讨
- 关于oracle字段到jsp前台显示验证中的长度限制问题