这些值在磁盘和内存中如何存储,要根据存储引擎的具体实现。
存储引擎存储char或者varchar值的方式在内存中和磁盘上可能不一样。
varchar用于存储可变长字符串。它比定长类型更节省空间。有一种例外,如果是用了row_format=fixed创建,那么每一行都会使用定长存储。
varchar需要使用1或2个额外字节记录字符串长度,如果列的最大长度小于或等于255字节,使用1个字节表示,否则使用2个字节表示。
因为行是变长的,在update时可能使行变得比原来更长,这就导致需要额外的工作。
如果一行占用的空间增长,并且在页内没有更多的空间可以存储,在这种情况下,不同存储引擎的处理方式是不一样的。
MyISAM会将行拆成不同的片段处理,InnoDB则需要分裂页来使行可以放进页内。
varchar大致适合下列的情况:
a.字符串的列最大长度比平均长度大很多
b.列更新的很少(所以碎片不是问题)
c.使用了复杂的字符集(例如UTF-8),每个字符都使用不同的字节数进行存储
MySQL 5.0或更高版本,存储和检索时会保留末尾空格。早期版本会剔除末尾空格。InnoDB则更灵活,它可以把过长的varchar存储为BLOB。
char类型是定长的。
当存储char值时,MySQL会剔除所有的末尾空格。char值会根据需要采用空格进行填充以方便比较。
char适合存储很短的字符串,或者所有值都接近同一个长度。例如char非常适合存储密码的md5值。
对于经常变更的数据,char也比varchar更好,定长的char类型不容易产生碎片。
对于非常短的列,char比varchar在存储空间上也更有效率。比如char(1)只需要1个字节,而varchar(1)则需要2个字节。
与char和varchar类似的还有binary和varbinary,他们存储的是二进制字符串。只不过二进制字符串存储的是字节码而不是字符。填充也不一样:MySQL填充binary采用的是\0(零字节)而不是空格,检索时也不会去掉填充
当希望使用字节码而不是字符进行比较时,这些类型非常有用。比较binary字符串时,每次按一个字节,并且根据字节的数值进行比较。
二进制比较字符比较简单,更快。
blob和text都是为存储很大的数据而设计的字符串数据类型,分别采用二进制和字符方式存储。
他们分别属于两组不同的数据类型家族:
字符类型包括tinytext,smalltext,text,mediumtext,longtext
二进制类型包括tinyblob,smallblob,blob,mediumblob,longblob
MySQL把每一个blob和text值当做一个独立的对象处理。当值太大时,innoDB会使用专门的外部存储区域存储实际的值。
blob和text家族之间仅有的不同是blob类型处处的是 二进制数据,没有排序规则或字符集,而text类型有字符集和排序规则。
MySQL对blob和text列进行排序与其他类型不同:它只对每列的最前max_sort_length字节而不是整个字符串做排序。如果只需要排序前面一小部分,则可以缩减max_sort_length的配置活着使用order by substring(column,lenth)。
枚举(enum)
有时候可以使用枚举列代替常用的字符串。
枚举列可以把一些不重复的字符串存储成一个预定义的集合。枚举在存储时非常紧凑,会根绝列表值得数量压缩到1个或者2个字节中。MySQL在内部将每个值在列表中的位置保存为整数,并在表的.frm文件中保存“数字-字符串”映射关系的查找表。
如果一个表中的字段e是枚举类型(有三个值,a,b,c),表内插入该字段值分别是a,b,c三条记录
查询如下:select e+0 from test;
查询结果:
+---------+
| e + 0 |
| 1 |
| 3 |
| 2 |
+---------+
如果使用数字作为enum枚举常量,这种双重性很容易导致混乱,例如enum('1','2','3'),建议避免。
查询如下:select e from test;
查询结果:
+---------+
| e |
| a |
| b |
| c |
+---------+
一种绕过这种现实的方式是按照需要的顺序来定义枚举列。也可以在查询中使用field()函数现实的指定排序顺序,但这回导致无法利用索引消除排序。
select e from text order by field(e,'a','b','c')
枚举最不好的地方是,字符串列表是固定的,添加或者删除字符串必须使用alter table。
对于一些列未来可能会改变的字符串,使用枚举不太好,除非能接受在列表末尾添加元素,这样就可以不用重建整个表来完成修改。
因为枚举值保存为整数,并且必须进行查找才能转换为字符串,所以枚举列有一些开销。通常枚举列都比较小,所以开销还可以控制。
特殊情况,char和varchar与枚举列关联可能比直接跟char或varchar关联还要慢。