欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

mysql 索引长度tips innodb和myisam引擎 有大用

  由于开发人员对索引认识不深或忽略,还有版本不同等问题,在生产环境中创建表失败,引发了一些问题。归纳了一下

    测试环境

       MySQL> select version();
+------------+
| version()  |
+------------+
| 5.5.31-log | 
+------------+
1 row in set (0.01 sec)

   innodb 引擎

mysql> CREATE TABLE `meta_topic_scan` (   `domain` varchar(257) NOT NULL,   `topic_name` varchar(200) NOT NULL,   `topic_url` varchar(200) NOT NULL,   `topic_pv` int(11) DEFAULT'0',   `topic_uv` int(11) DEFAULT '0',   PRIMARY KEY (`domain`,`topic_url`) ) ENGINE=innodb  DEFAULT CHARSET=utf8;

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

innodb 单列索引长度不能超过767 bytes,联合索引限制是3072 bytes 。对于创建innodb的组合索引中,如果各个列中的长度有单个超过767 bytes,也会创建失败;

myisam 引擎 

创建复合索引:

mysql> CREATE TABLE `meta_topic_scan` (

    ->   `domain` varchar(200) NOT NULL,
    ->   `topic_name` varchar(200) NOT NULL,
    ->   `topic_url` varchar(200) NOT NULL,
    ->   `topic_pv` int(11) DEFAULT '0',
    ->   `topic_uv` int(11) DEFAULT '0',
    ->   PRIMARY KEY (`domain`,`topic_name`,`topic_url`)
    -> ) ENGINE=myisam DEFAULT CHARSET=utf8 ;
ERROR 1071 (42000): Specified key was too long; max key length is 1000 bytes
创建单列索引:
mysql> CREATE TABLE `meta_topic_scan` (
    ->   `domain` varchar(334) NOT NULL,
    ->   `topic_name` varchar(200) NOT NULL,
    ->   `topic_url` varchar(200) NOT NULL,
    ->   `topic_pv` int(11) DEFAULT '0',
    ->   `topic_uv` int(11) DEFAULT '0',
    ->   PRIMARY KEY (`domain`)
    -> ) ENGINE=myisam DEFAULT CHARSET=utf8 ;
ERROR 1071 (42000): Specified key was too long; max key length is 1000 bytes
由此可知:myisam 单列索引长度、所创建的复合索引长度和都不能超过1000 bytes,否则会报错,创建失败。
另外不同字符集占用不同字节:latin一个字符占1 bytes,utf8存储一个字符占3 bytes, gbk存储一个字符2 bytes
扩展: innodb复合索引长度为什么是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):

 

 

 

扩展参考资料 http://dinglin.iteye.com/blog/1681332

来自 http://blog.csdn.net/aeolus_pu/article/details/9041487
 

有同学问到InnoDB的索引长度问题,简单说几个tips。

 

         关于3072

         大家经常碰到InnoDB单列索引长度不能超过767bytes,实际上联合索引还有一个限制是3072。

 

Sql代码  收藏代码
  1. mysql> CREATE TABLE `tb` (  

  2.     ->   `a` varchar(255) DEFAULT NULL,  

  3.     ->   `b` varchar(255) DEFAULT NULL,  

  4.     ->   `c` varchar(255) DEFAULT NULL,  

  5.     ->   `d` varchar(255) DEFAULT NULL,  

  6.     ->   `e` varchar(255) DEFAULT NULL,  

  7.     ->   KEY `a` (`a`,`b`,`c`,`d`,`e`)  

  8.     -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;  

  9. 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  。

来自  http://dinglin.iteye.com/blog/1681332


普通分类: