一、varchar设置为索引时的影响

MySQL建立索引时假设没有限制索引的大小,索引长度会默认采用该字段的长度。

也就是说varchar(20)和varchar(255)相应的索引长度分别为:20*3 + 2 + 1,255*3 + 2 + 1。当中"+2"用来存储长度信息,“+1”用来标记是否为空。

载入索引信息时用varchar(255)类型会占用很多其它的内存; (备注:当字段定义为非空的时候。是否为空的标记将不占用字节)

比如。测试sql(InnoDB引擎)例如以下:

CREATE DATABASE TestDataBase
USE TestDataBase
CREATE TABLE ABC (
  `id` int(11) DEFAULT NULL,
  `name` varchar(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
ALTER  TABLE  `ABC`  ADD  INDEX `nameIndex` (`name`)
explain select name from ABC
alter table ABC  modify name varchar(255)
explain select name from ABC

结果中的key_len表示索引使用的字节数,根据这个值可以判断索引的使用情况,特别是在组合索引的时候,判断该索引有多少部分被使用到非常重要。
在计算key_len时,下面是一些需要考虑的点:

  • 索引字段的附加信息:可以分为变长和定长数据类型讨论,当索引字段为定长数据类型时,如char,int,datetime,需要有是否为空的标记,这个标记占用1个字节(对于not null的字段来说,则不需要这1字节);对于变长数据类型,比如varchar,除了是否为空的标记外,还需要有长度信息,需要占用两个字节。
  • 对于,char、varchar、blob、text等字符集来说,key len的长度还和字符集有关,latin1一个字符占用1个字节,gbk一个字符占用2个字节,utf8一个字符占用3个字节。

综上,下面来看一些例子:

列类型

KEY_LEN

备注

id int

key_len = 4+1

int为4bytes,允许为NULL,加1byte

id bigint not null

key_len=8

bigint为8bytes

user char(30) utf8

key_len=30*3+1

utf8每个字符为3bytes,允许为NULL,加1byte

user varchar(30) not null utf8

key_len=30*3+2

utf8每个字符为3bytes,变长数据类型,加2bytes

user varchar(30) utf8

key_len=30*3+2+1

utf8每个字符为3bytes,允许为NULL,加1byte,变长数据类型,加2bytes

detail text(10) utf8

key_len=30*3+2+1

TEXT截取部分,被视为动态列类型。

备注:key_len只指示了where中用于条件过滤时被选中的索引列,是不包含order by/group by这一部分被选中的索引列的。
例如,有个联合索引idx(c1,c2,c3),3列均是int not null,那么下面的SQL执行计划中,key_len的值是8而不是12:

select ... from tb where c1=? and c2=? order by c1;

 

二、varchar(20)与varchar(255)都是保持可变的字符串,当使用ROW_FORMAT=FIXED创建MyISAM表时,会为每行使用固定的长度空间,这样设置不同的varchar长度值时。存储相同数据所占用的空间是不一样。

三、通常情况下使用varchar(20)和varchar(255)保持'hello'占用的空间都是一样的,但使用长度较短的列却有巨大的优势。较大的列使用很多其它的内存。由于MySQL一般会分配固定大小的内存块来保存值,这对排序或使用基于内存的暂时表尤其不好。相同的事情也会发生在使用文件排序或者基于磁盘的暂时表的时候。