MysQL 支持多种字符串类型,包括 VARCHAR 和 CHAR 类型、BLOB 和 TEXT 类型、ENUM(枚举)和 SET 类型。

VARCHAR 和 CHAR 类型

VARCHAR 和 CHAR 是两种最主要的字符串类型。

VARCHAR

  • VARCHAR 类型用于存储可变长字符串,是最常见的字符串数据类型。它比定长类型更节省空间,因为它仅使用必要的空间(例如,越短的字符串使用越少的空间)。在内部实现上,既然是变长,VARCHAR 需要使用 1 或 2 个额外字节记录字符串的长度,如果列的最大长度小于或等于 255 字节,则只使用 1 个字节表示,否则使用 2 个字节。
  • VARCHAR 节省了存储空间,所以对性能也有帮助。但是,由于行是变长的,在 UPDATE 时新值比旧值长时,使行变得比原来更长,这就肯能导致需要做额外的工作。如果一个行占用的空间增长,并且在页内没有更多的空间可以存储,在这种情况下,MyISAM 会将行拆成不同的片段存储,InnoDB 则需要分裂页来使行可以放进页内。

    CHAR

  • CHAR 类型是定长的,MySQL 总是根据定义的字符串长度分配足够的空间。

  • 当存储 CHAR 值时,MySQL 会删除所有的末尾空格,CHAR 值会根据需要采用空格进行填充以方便比较。

    对比

    在 CHAR 和 VARCHAR 的选择上,这些情况下使用 VARCHAR 是合适的: 字符串列的最大长度比平均长度大很多﹔列的更新很少;使用了像 UTF-8 这样复杂的字符集,每个字符都使用不同的字节数进行存储。
    CHAR 适合存储很短的字符串,或者所有值定长或都接近同一个长度。例如,CHAR 非常适合存储密码的 MD5 值,因为这是一个定长的值。对于经常变更的数据,CHAR 也比 VARCHAR 更好,因为定长的 CHAR 类型不容易产生碎片。
    对于非常短的列,CHAR 比 VARCHAR 在存储空间上也更有效率。例如用 CHAR( 1)来存储只有 Y 和 N 的值,如果采用单字节字符集只需要一个字节,但是VARCHAR(1)却需要两个字节,因为还有一个记录长度的额外字节。
    另外,使用 VARCHAR(5)和 VARCHAR(200)存储’hello’在磁盘空间上开销是一样的。我们随便选择一个就好?应该使用更短的列,为什么?
    事实证明有很大的优势。更长的列会消耗更多的内存,因为 MySQL 通常会分配固定大小的内存块来保存内部值。尤其是使用内存临时表进行排序或操作时会特别糟糕。在利用磁盘临时表进行排序时也同样糟糕。 所以最好的策略是只分配真正需要的空间

    BLOB 和 TEXT 类型

    BLOB 和 TEXT 都是为存储很大的数据而设计的字符串数据类型,分别采用二进制字符方式存储。
    与其他类型不同,MySQL 把每个 BLOB 和 TEXT 值当作一个独立的对象处理。
    存储引擎在存储时通常会做特殊处理。当 BLOB 和 TEXT 值太大时,InnoDB 会使用专门的外部存储区域来进行存储,此时每个值在行内需要 1~4 个字节存储一个指针,然后在外部存储区域存储实际的值。
    BLOB 和 TEXT 家族之间仅有的不同是 BLOB 类型存储的是二进制数据,没有排序规则或字符集,而 TEXT 类型有字符集和排序规则。

    使用 BLOB 和 TEXT 要慎重

    (1)BLOB 和 TEXT 值会引起一些性能问题,所以尽量避免使用 **BLOB **和 TEXT 类型
    (2)一定要用,建议把 BLOB 或 TEXT 列分离到单独的表中
    (3)在不必要的时候避免检索大型的 BLOB 或 TEXT 值。例如,SELECT *查询就不是很好的想法,除非能够确定作为约束条件的 WHERE 子句只会找到所需要的数据行。否则,很可能毫无目的地在网络上传输大量的值。建议可以搜索索引列,决定需要的哪些数据行,然后从符合条件的数据行中检索 BLOB 或 TEXT 值;
    (4)还可以使用合成的(Synthetic)索引来提高大文本字段(BLOB 或 TEXT)的查询性能。简单来说,合成索引就是根据大文本字段的内容建立一个散列值,并把这个值存储在单独的数据列中,接下来就可以通过检索散列值找到数据行了。但是,要注意这种技术只能用于精确匹配的查询(散列值对于类似“<”或“>=”等范围搜索操作符是没有用处的)。可以使用 MD5 函数生成散列值,也可以使用 SHA1(或 CRC32),或者使用自己的应用程序逻辑来计算散列值。

    必要时,使用枚举代替字符串

    如果表中的字段的取值是固定几个字符串,可以使用枚举列代替常用的字符串类型。
    枚举列可以把一些不重复的字符串存储成一个预定义的集合。MySQL 在存储枚举时非常紧凑,会根据列表值的数量压缩到一个或者两个字节中,MySQL 在内部会将每个值在列表中的位置保存为整数,这样的话可以让表的大小大为缩小。
    1. CREATE TABLE enum_test(e ENUM(' fish', 'apple', 'dog') NOT NULL);
    2. INSERT INTO enum_test(e) VALUES('fish'),('dog'),('apple');
    但是要注意
    1)因为枚举列实际存储为整数,而不是字符串,所以不要使用数字作为ENUM **枚举常量**,这种双重性很容易导致混乱,例如 ENUN( ‘1’, ‘2’, ‘3’)。
    2)枚举字段是按照内部存储的整数而不是定义的字符串进行排序的,所以尽量按照需要的顺序来定义枚举列。