MySQL数据类型——字符串类型(CHAR、BINARY、BLOB、TEXT、ENUM、SET)
发布日期:2021-06-29 22:33:12 浏览次数:2 分类:技术文章

本文共 12864 字,大约阅读时间需要 42 分钟。

一、字符串类型概述

  • 下图列出了MySQL支持的字符串数据类型

  • 字符串可以容纳任何内容,甚至能容纳那些用于表示图像和声音的二进制数据
  • 字符串可以按照大小写进行比较。此外,还可以对字符串进行模式匹配。(事实上,数字类型也支持模式匹配,只不过字符串类型的模式匹配更为常见一点。)​​

二、总体介绍

  • 字符串可以用于表示任何值;从这个意义上讲,它实际上是一种“范型”类型。例如,可以用二进制串类 型来存储二进制数据,如图像、声音、压缩后的gzip输出。
  • 下图列出了MySQL的所有用于定义字符串值列的类型,以及最大大小和存储空间要求:
    • M:表示列值的最大长度(二进制串以字节为单位,非二进制串以字符为单位)
    • L:表示某个给定值的字节长度
    • w:表示列字符集里最"宽"字符所占的字节数
    • BOLB和TEXT分别有多种变体,主要区别在于容纳的字符串最大长度不同

二进制与非二进制

  • 有些类型是用于保存二进制串(字节串),而其他类型则用于保存非二进制串。例如,BINARY(20)可以容纳20个字节,而CHAR(20)也可以容纳20个字符(对于多字节字符,其存 储空间要求肯定会超过20个字节)。
  • 关于二进制串和非二进制串在字节和字符语义方面的区别请参考
  • 每种二进制串类型都有一种与之对应的非二进制串类型,如下所示:

  • 每一种非二进制串类型,以及ENUM和SET类型,都可以指定具体的字符集和排序规则。对不同的列,可以指定不同的字符集。关于如何指定字符集请参考

固定长度类型

  • BINARY和CHAR都是固定长度的字符串类 型。对于这两种类型的列,MySQL将为每个值分配同样数量的存储空间
  • 并且会对那些比列的长度更短的值进行补齐:
    • 对于BINARY类型, 是使用0x00进行补齐。
    • 对于CHAR类型,则是使用空格
  • 因为CHAR(M)列必须能够表示由列的字符集所确定的最大可能字符串,所以这种类型列需要占用M×w个字节,其中,w是字符集里最宽字符所占用的字节数。
    • 例如,1个ujis字符会占用1〜3个字节 ,因此CHAR(20)必须分配60个字节的空间,以应对20个字符全部占用3个字节的情况。
    • 例如采用unicode字符集,每个英文字符占用1字节,如果定义一个列为CHAR(10),存储内容为'abc',该列仍占用10字节

可变长类型

  • 其他字符串类型的长度都是可变的。对于每个值所占用的存储空间大小,各个行也各不相 同;
  • 具体是多少,则取决于存储在列里的那些值的最大允许长度。对于可变长度的类型,这个长度在上图中被表示为L。除去L以外的额外要求字节空间,与用来存储值的长度所需的字节数相等。
  • 在处理长度可变的数据时 ,MySQL会把数据内容和数据长度都存储起来。这些额外的 “长度字节”前缀,会被当作无符号整数来对待。
  • 在可变类型的最大长度(即该类型所要求的长度字节数)与占用相同字节数的无符号整数类型的取值范围之间,存在着一定的对应关系例如,MEDIUMBLOB类型值的最大长度是2^{24}-1个字节,并且需要3个字节来记录这个长度。而对于占用3个字节的整数类型MEDIUMINT,其最大无符号值也为2^{24}-1。这可不是什么巧合!
  • 对于VARBINARY和VARCHAR类型,如果列值的最大字节长度小于256,那么其长度前缀将占用1个字节,否则,将占用2个字节。
  • 除了ENUM和SET这两种类型以外,MySQL会将其他所有字符串类型的值存储为一串字节;并且它还会根据所存储字符串的具体类型(二进制或非二进制),把这些字节解释为字节串或字符串。如果这些值的长度太长,导致无法存储,那么会截断它们 。(在严格模式下,只有截断后的字符为空格的情况下,才会有错误提示。)不过,因为各种字符串类型的大小各异 (最大的类型能够容纳将近4GB的数据),所以在理论上完全可以找到一种很长的字符串类型,用于存储各种长数据,从而避免信息被截断 。(实际上,字符串类型列的最大有效长度,取决于MySQL的 “客户端/服务 器”通信协议所支持的最大数据包长度,其默认值为1MB。)
  • 对于ENUM和SET类型,其列定义里都有一个合法字符串值的列表,但ENUM和SET的值在内部都被存储为数字,更多相关细节在下面会介绍。在未启用严格模式的情况下,如果把某个未出现在列表里的值存储到ENUM或SET类型列里,则会导致该值被转换为一个空串(' ')。在严格模式下,这会导致出现错误。

三、CHAR、VARCHAR

  • 字符串类型CHAR和VARCHAR主要用于保存非二进制串,因此它们有字符集和排序规则 。
  • CHAR和VARCHAR之间的主要区别在于:它们的长度是固定的,还是不变的;如何对待尾部空格。
    • CHAR是一种长度固定的类型,而VARCHAR是一种长度可变的类型。
    • 从CHAR列检索出来的值,其尾部空格会被移除。对于CHAR(M)列,如果其值的长度小于M个字符,那么在存入时会用空格将长度补齐到M。但是,当在检索这些值时,其尾部的空格会被移除。如果启用SQL的PAD_CHAR_TO_ FULL_LENGTH模式,那么在检索CHAR列值 时就可以保留尾部空格。
    • 对于VARCHAR列,其尾部空格在存储和检索时都会被保留

CHAR长度

  • 在定义CHAR列时 ,其最大长度M的取值范围是0~255
  • 对于CHAR类型,M是可选的;如果省略,则其默认值为1
  • 请注意,CHAR(0)也是合法的。如果你允许CHAR(0)列为NULL,那么它可以用它来表示“开/关”值 。这种列只有两种取值:NULL或空串。在表里,CHAR(0)列只占用非常少的存储空间——仅一个二进 制位。

VARCHAR长度

  • 对于于VARCHAR(M),其中的M在语法上的取值范围是1~65535,但它实际能够容纳的最大字符个数肯定小于65535。这是因为在MySQL里,行的最大长度为65535个字节。
  • 下面是一些潜在的影响点:
    • 一个长VARCHAR列需要2个字节来存放字符串的长度,最终长度不能超过行的总长。
    • 使用多字节字符可以减少字符个数,从而使字符总长度不会超过最大行长度。
    • 表里的其他列也会减少行里VARCHAR列的可用空间量。
  • CHAR和VARCHAR这两种数据类型的选择:
    • 如果所有值的长度都是M个字符,那 么VARCHAR(M)列会比CHAR(M)列多占用存储空间,因为前一种类型还需要用额外的字节来记录值的长度。
    • 反之,如果数据长短不一,那么选用VARCHAR类型可以节省空格占用的存储空间。CHAR(M)列始终会占用M个字符的空间,即使其值为空或NULL也一样。
    • 如果使用的是MylSAM表,并且各个值的长度差别不大,那么选用CHAR往往会比选用VARCHAR更好些,因为MylSAM存储引擎对固定长度行的处理效率,要比对长度可变行的高。更多相关信息在后面"选择利于高效查询的表存储格式"会介绍。

四、BINARY、VARBINARY

  • BINARY和VARBINARY类型与CHAR和VARCHAR相似,不同之处在于以下几点:
    • CHAR和VARCHAR都是用于存储字符的非二进制类型,并且都字符集和排序规则。比较 操作依据的是排序序列
    • BINARY和VARBINARY都是用于存储字节的二进制类型,它们没有字符集和排序规则。比较操作依据的是字节值的大小
  • 对于BINARY(M)列,当存储那些长度短于M个字节的值时,它们会用0x00字节进行补齐,以保证 长度为凡在检索时,不会去除任何内容。对于VARBINARY,在存储值时,不会进行补齐;在检 索时,也不会去除任何内容。

五、BLOB、TEXT

BLOB

  • “blob”指的是二进制大对象(binary large object),它实际上是一个能够存放任何内容的容器,并且可以大到超出你的想象,多达4GB。
  • 在MySQL里,BLOB类型实际上是一个类型家族,它包括TINYBLOB、BLOB、MEDIUMBLOB和 LONGBLOB。除各自所能存放的最大信息量不同以外,这些类型在其他方面完全一致。
  • BLOB列存储的是二进制串。如果要保存的信息有可能会急剧膨胀 ,或者各行的长短差异很大,那么BLOB类型会非常适合。像压缩数据、加密数据、图像和声音,都适合使用BLOB。

TEXT

  • MySQL还有一个TEXT类型家族,它包括TINYTEXT、TEXT、MEDIUMTEXT和LONGTEXT。
  • 它们与相应的BLOB类型有很多相似之处,但TEXT类型存储的是非二进制串,而非二进制串。也就是说,它们存储的是字符,而不是字节,它们与字符集和排序规则相关联。这也是二进制串和非二进制串的不同之处。例如,BLOB值的比较是以字节为单位的;而TEXT值的比较则是以字符为单位,并且依据的是列的排序规则 。
  • 不过,TEXT类型的最大长度与BLOB类型的是一样的。也就是说 ,它们都是以字节为单位来衡量最大长度的,而不是以字节为单位(对于BLOB类型)和以字符为单位(对于TEXT类型)进行衡量。
  • BLOB和TEXT列能否被索引,具体取决于所使用的存储引擎
    • 存储引擎InnoDB和MylSAM都支持对BLOB和TEXT列进行索引。但必须指定一个前缀长度,以方便索引使用。这样可以避免创建出可能会过于庞大的索引,如果出现这样的情况,则会完全抵消掉索引所带来的好处。不过凡事有例外,TEXT列的FULLTEXT索引并不会使用那个前缀长度,因为FULLTEXT索引是以索引列的完整内容为基础的,指定的前缀长度会被忽略。
    • MEMORY表不支持BLOB和TEXT索引,因为MEMORY引擎根本不支持BLOB和TEXT列。
  • 对于BLOB或TEXT列,需要特别注意以下几点
    • 由于BLOB和TEXT列里的值在长度方面的差异通常很大,因此在多次执行删除和修改操作之后,表里容易产生大量碎片。如果是使用MylSAM表来存储BLOB或TEXT值 ,那么定期运行OPTIMIZE TABLE命令可以减少碎片和改善系统性能。更多相关信息请参考后面"查询优化"相关文章。
    • max_sort_length系统变量会对BLOB和TEXT类型值的比较和排序操作产生影响。对于每个值,只有其前面的max_sort_length个字节才会被使用到。 (这意味着,对于使用了多字节字符集的TEXT列,参与比较 的字符数会少于max_sort_length。)如果max_sort_length的默认值 (为1024)会造成问 题,则可以在执行比较之前把它调大。
    • 对于数据量非常大的值,可能需要配置MySQL服务器,增大max_allowed_packet参数的值。更多相关信息在后面"服务器调整"文章会介绍。对于所有想要使用大数据量值的客户端程序,则需要在客户端增大数据包的大小。客户端程序mysql和mysqldump都支持直接使用启动选项来设置这个值。

六、ENUM、SET

  • ENUM和SET是比较特殊的字符串数据类型,它们只能从一个固定的(预先定义好的)字符串列表里取值。
  • 这两种类型的主要区别是:ENUM列值必须包含且只能包含一个值列表成员,而SET列值则允许包含任意多个值列表成员 (可以为空,也可以是全体 成员 )。换句话说,enum类型的值不允许同时出现,而SET类型的值允许同时出现

ENUM

  • ENUM类型定义的是枚举集合,它最多允许有65535个成员。赋给ENUM列的值只能是你在创建表时指定的值列表中的一个成员。
  • 枚举类型通常用于表示类别值。例如,对于某个定义为 ENUM('N', 'Y')的列,其值可以是'N'或 'Y'。另外,你也可以将ENUM类型用于表示某种产品的尺寸或颜色,或者用于表示某次调査问卷中的多重选择题的答案(仅限单选):
employees ENUM('less than 100', '100-500', '501-1500', 'more than 1500')color ENUM('red', 'green', 'blue', 'black')size ENUM('S', 'M', 'L', 'XL', 'XXL')vote ENUM('Yes', 'No', 'Undecided')
  • 如果你正在处理来自Web页面的选择项,而该页面包含了很多互斥单选按钮,那么你可 以使用ENUM来表示这些让网站的访问者可以从中进行选择的选项。
  • 例如,你正在运营一个在线比萨饼订购服务,这时就可以用一个ENUM列来表示顾客所订比萨饼的口味和大小
crust ENUM('thin', 'regular', 'pan style', 'deep dish')size ENUM('small', 'medium', 'large')

SET

  • SET类型与ENUM类型有相似之处,如在创建SET列时,同样需要为它指定一个所允许的 集合成员列表。SET类型最多允许有64个成员
  • 它与ENUM类型有所不同,其每一个值列都可以由集合的任何成员构成。如果有一组固定值,但与在ENUM列里的情况不同,它们不是互斥的,这时就可以使用SET。
  • 例如,上面那个在线比萨饼服务可能会有一组多选框 ,用于表示顾客想要的用作馅料的配料,而且可以有多种选择。这时就可以使用SET来表示这些配料
SET('pepperoni', 'sausage', 'mushrooms', 'onions', 'ripe olives')
  • 于是,特定的SET值就代表了顾客实际所选择的那些配料:最后一个值(空串)表示顾客在订购时没有选择任何配料,SET是允许这样的。
'pipperoni,mushrooms''sausage,onions''sausage,mushrooms,ripe olives''onions'''
  • SET定义时的相关注意事项:
    • SET列的定义 ,可以写成以逗号分隔的单个字符串列表,表示所有的集合成员。
    • 另 一方面,SET列的值 ,必须是一个字符串。如果这个值由集合里的多个成员构成,则必须用逗号把各个成员分隔开。这意味着,你不应该把一个包含逗号的字符串用作SET的成员。
  • 在为ENUM或SET列定义合法取值列表时,必须考虑到以下几个因素:
    • 这个列表确定了列的所有允许值,之前已经讨论过这一点。
    • 如果ENUM或SET列带有一个不区分大小写的排序规则 ,那么在插入合法值时也不用区分大小写,它们都能够被识别出来 。但是,当在检索ENUM或SET列里的数据时 ,它们将按照列定义的合法取值列表里的字母大小写形式来显示。例如,定义了一个ENUM('Y', 'N')列,那么 完全可以插入'y'和'n';但在检索时,它们会显示为'Y'和'N'。如果这个列带有区分大小写的排序规则或二进制排序规则,那么在插入数据时,必须严格按照列定义里的大小写字母来书写;否则,它们会被服务器当作是非法的。另一方面,的确可以根据成员大小写的不同来区 分它们,但是当你使用不区分大小写的排序规则时,这种做法就不可行了。
    • ENUM定义里的值的顺序就是排序所用的顺序。SET定义里的值的排序也确定了排序顺序,只是关系更为复杂些,因为其列值可能包含多个集合成员 。
    • 当MySQL显示某个由多个集合成员构成的SET值时,这些成员的列出顺序由它们在SET列定义里的顺序确定
  • 在创建ENUM和SET类型列时 ,需要以字符串的形式列出枚举和集合成员 ,因此它们都被归类为字符串类型。但是,ENUM和SET类型实际上有点“人格分裂”:
    • 它们的成员在内部的存储形式是数字,并且也可以把它们当作数字来对待。
    • 这意味着,ENUM和SET类型要比其他字符串类型有着更好的处理性能,因为它们可以使用数字操作来代替字符串操作进行处理。
    • 同时也意味着,ENUM和SET值可以用在字符串环境里,也可以用在数字环境里
    • 最后还有一点,如果在字符串环境里使用ENUM和SET列,但是希望它们表现得像数字(或者是情况刚好相反),那么它们可能会引起混乱
  • MySQL将从1开始依次对ENUM列定义里的成员进行顺序编号。(编号0被保留为出错代码,其字符串形式即为一个空串)。
  • ENUM列占用的存储空间大小由枚举值的个数确定:
    • 1个字节可以表示256个值,2个字节能表示65536个值。(请试着将它们分别与占用1个字节的整数类型TINYINT UNSIGNED的取值范围和占用2个字节 的整数类型SMALLINTUNSIGNED的取值范围作个对比)。
    • 因此,在加上那个出错代码之后,枚举成员的最大数目是65536个,而对于它所占用的存储空间是1个字节还是2个字节,则取决于成员数是否超过256个。
    • 因为MySQL需要为出错代码预留1个位置,并将它作为每一个枚举的隐含成员,所以在定义里最多能够指定的是65535(而非65536)个成员。当把某个非法值放入ENUM列时,MySQL会赋值为那个出错成员。(在严格模式下,会产生一个错误)。
  • 下面这个示例演示了以字符串方式和数字方式检索ENUM值的情况 (它会显示枚举成员的序号;NULL值没有序号):
CREATE TABLE e_table (e ENUM('jane', 'fred', 'will', 'marcia'));INSERT INTO e_table VALUES('jane'),('fred'),('will'),('marcia'),(NULL);SELECT e, e+0, e+1, e*3 FROM e_table;

  • 也可以按名字或编号对ENUM成员进行比较:
SELECT e FROM e_table WHERE e='will';SELECT e FROM e_table WHERE e=3;

空串

  • 也可以把空串定义为有效的枚举成员,不过这个时候需要多加注意。这个字符串被赋值为一个非零值,与该定义里列出的其他成员没什么两样。但是,空串也被用于那个数值为0的错误成员,因此它会对应到两个内部数字元素值。
  • 在下面的示例里,当把非法枚举值'x'插到ENUM列时,它会被赋值为出错成员。只有以数字形式检索,才能把列定义里的空串成员区別出来:
CREATE TABLE s_table (s SET('table','lamp','chair','stool'));INSERT INTO s_table VALUES('table'),('lamp'),('chair'),('stool'),(''),(NULL);SELECT s, s+0, BIN(s+0) FROM s_table;

  • 当把值'lamp,stool'赋给s列时,MySQL会在其内部把它存储为10(二进制数1010),因为 'lamp'的数值是2(第1位),'stool'的数值是8(第3位)。

  • 在对SET列进行赋值时 ,其中各个子字符串的顺序不用与定义这个列时所用的顺序完全一样。不过 ,在以后的检索操作中,这个成员是按它们在声明里的先后顺序显示的。此外,在给SET列赋值时 ,如果这个值包含的某些子字符串不属于集合成员 ,那么这些子字符串会被剔除掉,剩余的子字符串会被赋给这个列。以后检索这个值时,也看不到那些非法子字符串。
  • 如果把'chair,couch,table'赋值给s_table表里的s列,那么会发生两件事:
    • 'couch'会被剔除掉,因为它不是集合成员。之所以如此,是因为在赋值过程中, MySQL会为每一个值的子字符串确定出与之对应的二进制位,并把它们组合成存储值。既然不存在与'couch'相对应的二进制位,那么它便会被忽略掉了。
    • 将来检索这个值时,它将显示为'table,chair'。在检索时,MySQL会按顺序扫描各个位,并根据数字值构造出对应的字符串值,同时,还会按照列定义里的顺序对子字符串自动重排。这种重排行为还意味着:即使你把某个值多次赋给一个SET列,它在检索结果里也只会出现一次。也就是说 ,如果把'lamp,lamp,lamp'l赋值给SET列,那么在检索时也只会看到一个'lamp'。
  • 在严格模式下,使用非法SET成员将导致错误,并且这个值也不会被存储。在前面的示例里,当赋予某个包含'couch'的值时,会引发一个错误,并且赋值操作也会失败。
  • MySQL会重排SET列值里的成员,这一事实说明:如果要搜索那些使用字符串的值 ,那么必须 按正确的顺序列出各个成员。例如,先插入'chair, table',然后搜索'chair,table',那么最终是无法找到这行的;必须使用'table, chair'来查找才行。
  • ENUM和SET列的排序和索引操作都是按列值的内部值 (即数字值)执行的。下面这个示例表面看起来不正确 ,因为这些值没有按字母顺序显示,但它实际毫无问题:
SELECT e FROM e_table ORDER BY e;

  • 为了更好看清是怎么回事,下面同时检索ENUM值的字符串形式和数字形式:
SELECT e, e+0 FROM e_table ORDER BY e;

  • 如果有一组固定值,而你想按某种顺序对它们进行排序,那么可以利用ENUM类型的排序性。即先将这些值表示为某个表里的一个ENUM列,并在该列的定义里按照你想要的顺序依次列出各个值 。 假设你用一个表来表示某个运动组织(如橄榄球队)的个人信息,而且你想要根据个人的位置来对输出结果进行排序,以便按特定的顺序(如教练、助理教练、四分卫、跑锋、接球手、边线防守队员等)进行输出。那么,你可以把这个列定义为ENUM类型的,并按你想要的顺序列出各个枚举成员。然后,在各种排序操作中,这些列值便会自动按事先设定的顺序输出。
  • 如果想让某个ENUM列按常规的字母表顺序排序,那么可以先用CAST()函数把这个列的值转换 为一个非ENUM的字符串,然后再对结果进行排序:
SELECT CAST(e AS CHAR) AS e_str from e_table ORDER BY e_str;

  • CAST()函数并没有更改这些显示值,它在这条语句里的作用只是完成了一个从ENUM到字符串的转换操作——它会改变这些值的排序特性,从而可以按字符串方式进行排序。

七、字符串数据类型属性

  • 字符串数据类型特有的属性有CHARACTER SET (或CHARSET)和COLLATE,它们分别用于指定字符集和排序规则 。你可以把它们指定为表自身的默认选项;也可以指定为各个列的单独选 项,从而改写表的默认选项 。(事实上,与服务器一样 ,每个数据库都有默认的字符集和排序规 则。这些默认选项在创建表时能发挥一定作用,稍后即将看到。)
  • CHARACTER SET和COLLATION属性适用的数据类型有CHAR、VARCHAR、TEXT、ENUM和 SET。它们并不适用于二进制串数据类型(BINARY、VARBINARY和BLOB) ,因为这些类型包含 的是字节串,而非字符串。
  • 在指定CHARACTER SET和 COLLATION属性时,不管是在列、表和数据库这三级别中的哪一级 ,都要遵从以下规则:
    • 使用的字符集必须是服务器支持的。使用SHOW CHARACTER SET语句可以査出当前可用的字符集。
    • 如果定义里同时使用了CHARACTER SET和COLLATION属 性,那么它们所代表的字符集和排序规则必须要相兼容。例如,对于字符集latin2,排序规则可以使用latin2_croatian_ci,但不能使用latin1_bin。使用SHOW COLLATION语句可以把每一种字符集所支持的排序规则 显示出来。
    • 如果定义里只有CHARACTER SET,而没有COLLATION,则使用默认排序规则
    • 如果定义里只有COLLATION,而没有CHARACTER SET,那么具体的字符集就要由排序规 则名的第一部分来确定。

演示案例

  • 创建下面的一张表,使用多种字符集和排序规则:
CREATE TABLE mytbl(    c1 CHAR(10),    c2 CHAR(10) CHARACTER SET latin2,    c3 CHAR(10) COLLATE latin1_german1_ci,    c4 BINARY(40))character set UTF8;

  • 最终的表将使用utf8作为其默认字符集。因为没有给出表选项COLLATION,所以默认的表排序规则 为utf8字符集的默认排序规则(即utf8_genaral_ci)。
  • 因为c1列的定义里没有包含CHARACTER SET属性和COLLATION属性,所以它将使用表的默认设置。
  • c2、c3和c4列没有使用表级的字符集和排序规则:因为 C2和 C3列有它们自己的字符集信息,而c4列有二进制串类型,因此那些字符集属性对它们不适用。c2列的排序规则是latin2_general_ci,这 是字符集latin2的默认排序规则 。c3列的字符集是latin1,它是根据该列的排序规则名latin1_german_ci确定的。
  • 可以通过下面的语句查看表的字符集信息:
    • 如果SHOW CREATE TABLE没有显示列的字符集,则表明它与表的默认字符集相同
    • 如果它没有显示列的排序规则,则表明该列的排序规则与该列的字符集默认排序规则相同。
SHOW CREATE TABLE mytbl\G

  • 也可以给SHOW COLUMNS语句加上关键字FULL,用于显示排序规则信息(可以根据它推断出具体的字符集):

SHOW FULL COLUMNS FROM mytbl;

binary字符集

  • 字符集名binary比较特殊。当将某个非二进制串列指定为binary字符集时 ,相当于把该列定义为相应的二进制串类型。在下面几对 列定义 里,每一对里的那两条语句都是等价的:
c1 CHAR(10) CHARACTER SET binaryc1 BINARY(10)c2 VARCHAR(10) CHARACTER SET binaryc2 VARBINARY(10)c3 TEXT CHARACTER SET binaryc3 BLOB
  • 如果为某个二进制串列指定了CHARACTER SET binary,那么它将被忽略,因为该类型已经 是二进制类型了。如果为ENUM或SET列指定了CHARACTER SET binary,那么它将像前面讨论的那样发挥作用
  • 如果把binary字符集赋值为表选项,那么它将应用到所有在其定义里没有指定任何字符集信息的字符串列。
  • 对于字符列定义的属性,MySQL还提供了多种简写形式
    • ASCII属性是CHARACTER SET latin1的简写 。
    • UNICODE属性是CHARACTER SET ucs2的简写 。
    • 如果为某个二进制串列指定了BINARY,那么它将被忽略,因为该类型已经是二进制类型了。
    • 对于非二进制串列、ENUM列或SET列,如果指定BINARY属性,则等同于在指定该列字符集的二进制排序规则 。例如,某个表的默认字符集为latin1,则以下这些定义是等效的:
c1 CHAR(10) BINARYc1 CHAR(10) CHARACTER SET latin1 BINARYc1 CHAR(10) CHARACTER SET latin1 COLLATE latin1_bin

NULL

  • 任何字符串类型都能使用通用属性NULL或NOT NULL。如果没有指定,则默认为NULL
  • 不过,把一个字符串列声明为NOT NULL,并不意味着它不能存储空字符串(即'')。在MySQL里,空值与没有值是有区别的。因此,千万不要因为某个字符串列声明成NOT NULL,就错误地认为它包含的是非空值。如果想让所有字符串值全部为非空,则必须在应用程序里实施这样的限制。

DEFAULT

  • 也可以使用DEFAULT子句,为除BLOB和TEXT类型外的其他字符串数据类型指定默认值。

七、选择字符串数据类型

  • 在为字符串列选择数据类型时,请认真考虑以下几个问题。

这些值是要表示为字符数据,还是二进制数据?

  • 如果答案是字符数据,则选择非二进制串类型最为合适。
  • 如果答案是二进制数据,则选用二进制串类型。

比较操作需要区分大小写吗?

  • 如果是,则应该选用一种非二进制串类型,因为这些存储字符,与字符集和排序规是相关联的。
  • 非二进制串值在比较和排序时是否区分大小写 ,受制于为它们指定的排序规则
    • 如果不想区分大小写,则应该选用一种不区分大小写的排序规则。
    • 否则,应该选用一种二进制排序规则或区分大小写的排序规则 。
  • 二进制排序规则在比较两个字符时,使用的是它们的数值编码。区分大小写的排序规则在比较两个字符时,使用的是该种排序规则特有的字符顺序——它不一定与字符编码的大小顺序相同。对于这两种情况,给定字符的小写和大写版本在比较操作中会被认为是不同的:
    • 假设 ,字符串'mysql','MySQL'和'MYSQL'都是latin1字符集。
    • 如果使用某种不区分大小写的排序规则 ,如latin1_swedish_ci,那么它们将被认为是相同的。
    • 如果使用二进制排序规则latin1_bin或某种区分大小写的排序规则latin1_general_cs,则它们是三种不同的字符串。
  • 如果需要使用到的列里既有区分大小写的比较 ,又有不区分大小写的比较,则使用的排序规 则要与你最常执行的比较类型相对应 。对于其他类型的比较 ,则可以利用COLLATE运算符来更改排序规则。例如,如果mycol是一个使用latin1字符集的CHAR列,则可以选择 latin1_swedish_ci作为不区分大小写比较的默认排序规则 。下面的比较操作不区分大小写:
mycol = 'ABC'
  • 当需要区分大小写的比较时,可以使用排序规则latin1_general_cs或latin1_bin。下面的比较 操作会区分大小写(COLLATE运算符可以放在左边的字符串上,也可以放在右边的字符串上,效果是一样的):
mycol COLLATE latin1_general_cs = 'ABC'mycol COLLATE latin1_bin = 'ABC'mycol = 'ABC' COLLATE latin1_general_csmycol = 'ABC' COLLATE latin1_bin

想要少占用存储空间吗?

  • 如果是,则可以选用一种可变长度的类型,而不要选用固定长度的类型。

列的取值总是从固定的某些值里选取吗?

  • 如果是,则ENUM或SET可能是最好的选择 。
  • 如果字符串值是一个有限集合,并且想按照某种非字母表顺序对它们进行排序,那么ENUM类型会非常有用。对ENUM值的排序依据的是列定义里那些枚举值的排列顺序,因此可以按你所期望的任何顺序让这些值进行排序。

尾部的填充值很重要吗?

  • 如果要求数据必须原样存入和取出,不能增加和移除尾部的空格 (对二进制数据类型,具体 值为字节0x00),那么应该选用TEXT或VARCHAR列来存放非二进制串,而选用BLOB或 VARBINARY列来存放二进制串
  • 当想要存储压缩数据、散列数据或加密数据时,这一点非常关键 ,因为它们的编码方法可能会导致尾部空格
  • 下图展示了MySQL如何处理各种字符串数据类型在存储和检索数据时的尾部填充问题

  • 启用SQL模式PAD_CHAR_TO_FULL_LENGTH,可以让检索出来的CHAR列值保留尾部空格。

转载地址:https://dongshao.blog.csdn.net/article/details/104030996 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Effective STL第7条:容器之(如果容器内元素通过new创建,切记在容器对象析构前将指针delete掉(使用智能指针))
下一篇:C++(对象模型):08---Function之(Function Member的各种调用方式(静态函数、非静态函数、虚函数)、附C++的mangling机制)

发表评论

最新留言

逛到本站,mark一下
[***.202.152.39]2024年04月11日 12时08分14秒