开domain会议时候提到的mysql字符串大小的计算,让我想到了曾经回答SSC计算oracle字符长度的问题,难道mysql计算不一样?临下班时,尝试了下,终于弄懂了。闲话少叙(= =#)直奔主题吧。
首先说oracle吧,SSC说他存了一个字符串报出系统错误,查看log,发现是字符串过长导致。发现字段类型为varchar2(1000),表明可以最多可以存放1000个字节,已经很大了。但是为什么会报长度不够呢,看他给的字符远没有1000那么多。后来发现他给的字符串中有太多的中文顿号,虽然总长度没有达到1000,但是考虑到一个中文字符占得字节可是双倍(gbk,utf-8编码会是三倍),所以建议他将中文顿号改为英文后成功存入。上述声明表明括号中为字节的长度大小。当然还有一种申明是varchar2(1000 char),这种就表示存放1000个字符。但是这种要特别注意:oracle中字符串类型最大4000字节,所以如果申明这种字符的方式的话,一定要注意不能存太多汉字,否则很容易超出4000字节。所以保险的做法就是varchar2(2000 char),并且是gbk编码的话,这样能保证在4000以内。那么mysql是不是也是这样呢?实验如下:
我们创建表的时候会给字段指定空间大小。int(1),char(20),varchar(20)等。那么varchar(20)到底是多大呢?20是字符数还是字节数?
用事实说话:
执行结果如下:
结果只有以上三条记录。三个汉字和两个汉字带一个字符的都报出超出column长度。如果是字节数的,我们知道utf8中一个汉字占三个字节,varchar(2)如果表示两个字节的话,肯定是不能存一个或者两个汉字的。所以这里面肯定不是指字节数。通过以下查询:
select name,length(name),char_length(name) from test1;
得出:
从表中可以看出一个汉字占三个字节,一个字符占一个字节。所以varchar中的数字表示字符数,无论是汉字还是字符。但是它的大小取决于存的数。所以会出现同一列的值占的空间大小不一样,也就是说同样的字符串列,mysql的值可以达到很大很大但是不会超过[(65535-2)/3]个字节。