MySQL数据类型之字符串(char和varchar)

    varcharchar是两种最主要的字符串类型

    这些值在磁盘和内存中如何存储,要根据存储引擎的具体实现。

    存储引擎存储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类似的还有binaryvarbinary,他们存储的是二进制字符串。只不过二进制字符串存储的是字节码而不是字符。填充也不一样:MySQL填充binary采用的是\0(零字节)而不是空格,检索时也不会去掉填充

        当希望使用字节码而不是字符进行比较时,这些类型非常有用。比较binary字符串时,每次按一个字节,并且根据字节的数值进行比较。

       二进制比较字符比较简单,更快。

blobtext都是为存储很大的数据而设计的字符串数据类型,分别采用二进制字符方式存储。

        他们分别属于两组不同的数据类型家族:

        字符类型包括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关联还要慢。

发布了95 篇原创文章 · 获赞 3 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/bigwood99/article/details/105496709