认识mysql字符集

    z字符集是指一种从二进制编码到某类字符符号的映射;“校对”是指一组用于某个字符集的排序规则。mysql对各种字符集的支持都非常完善,但是这也带来了一定的复杂性。

一、mysql如何使用字符集

    每种字符集都可能有多重校对规则,并且都有一个默认的校对规则。每个校对规则都是针对某个特定的字符集的,和其他的字符集没有关系。校对规则和字符集总是一起使用的。mysql有很多选项用于控制字符集。这些选项和字符集很容易混淆,牢记:只有基于字符的值才真正的“有”字符集的概念。对于其他类型的值,字符集只是一个设置,指定用哪一种字符集来做比较或者其他操作。基于字符的值能存放在某列中、查询的字符串中,表达式的计算结果中或者某个用户变量中。

    mysql的设置可以分为两类:创建对象时的默认值、在服务器和客户端通信是的设置。

1、创建对象时的默认设置

    mysql服务器有默认的字符集和校队规则,每个数据库也有自己的默认值,每个表也有自己的默认值。这是一个逐层继承的默认设置,最终最底层的默认设置将影响你创建的对象。这些默认值,至上而下告诉mysql应该使用什么字符集来存储某个列。

    在每一层,都可以指定一个特殊的字符集或者让服务器使用它的默认值:

  • 创建数据库的时候,将根据服务器上的character_set_server设置来设定该数据库的默认字符集;
  • 创建表的时候,将根据数据库的字符集设置指定这个表的字符集设置;
  • 创建列的时候,将根据表的设置指定列的字符集设置。

    真正存放数据的是列,所以更高层的设置只是指定默认值。一个表的默认字符集设置无法影响存储在这个表中某个列的值。只有当创建列而没有为列指定字符集的时候,标的默认字符集才有作用。

2、服务器和客户端通信的设置

    当服务器和客户端通信的时候,他们可以使用不同的字符集。这时,服务器端将进行必要的翻译转换工作:

  • 服务器端总是设置客户端是按照character_set_client设置的字符来传输数据和SQL语句的;
  • 当服务器接受到客户端的SQL语句时,它先将其转换成字符集character_set_connection。它还是用这个设置来决定如何将数据转换成字符串。
  • 当服务器端返回数据或者错误信息给客户端时,它会将其转换成character_set_result。

    根据需要可以使用set names或者set character set语句来改变上面的设置。不过在服务器上使用这个命令只能改变服务器端的设置。客户端程序和服务端的API也需要使用正确的字符集才能避免在通信时出现问题。


     假设使用Latin1字符集打开一个连接,并使用set names utf8来告诉服务器客户端将使用utf-8字符集来传输数据。这样就创建了一个不匹配的字符集,可能会导致一些错误甚至出现一些安全性问题。应当先设置客户端字符集然后使用函数mysql_real_escape_string()在需要的时候进行转义。在php中,可以使用mysql_set_charset来修改客户端的字符集。

3、特殊使用

  • 诡异的character_set_database设置:character_set_database设置的默认值和默认数据库的设置相同。当改变默认数据库的时候,这个变量也会跟着改变。所以当连接到mysql实例上又没有指定要使用的数据库时,默认值和character_set_server相同。
  • load data infile:当使用load data infile的时候,数据库总是将文件中的字符按字符集character_set_database来解析。在mysql 5.0和更新的版本中,可以在load data infile中使用子句character set来设定字符集,不过最好不要依赖这个设定。最好的方式是先使用use指定数据库,再执行set names来设定字符集,最后在加载数据。mysql在加载数据的时候,总是以同样的字符集处理所有数据,而不管表中的列是否有不同的字符集设定。
  • select into outfile:mysql会将select into outfile的结果不做任何转码的写入文件。目前,除了使用函数convert()将所有的列都做一次转码外,还没有什么特别的办法能够指定输出的字符集。
  • 嵌入式转义序列:mysql会根据character_set_client的设置来解析转义序列,即使字符串中包含前缀或者collate子句也一样。这是因为解析器在处理字符串的转义字符时,完全不关心校对规则。

二、选择字符集和校对规则

    mysql支持很多字符集和校对规则,包括支持使用Unicode编码的多字节utf-8字符集。可以使用命令show character set和show collection来查看mysql支持的字符集和校对规则。

    对于校对规则通常需要考虑一个问题:是否以大小写敏感的方式比较字符串,或者以字符串编码的二进制值来比较大小。他们对应的校对规则的前缀分别是_cs、_ci和_bin,根据需要很容易选择。大小写敏感和二进制校对规则的不同之处在于,二进制校对规则直接使用字符的字节进行比较,而大小写敏感的校对规则则在多个字节字符集时,如德语,有更复杂的比较规则。

    在显示设置字符集的时候,并不是必须同时指定字符集和校对规则的名称。如果缺失了其中一个或者两个,mysql会使用可能的默认值来进行填充。

三、字符集和校对规则如何影响查询

    某些字符集和校对规则可能会需要更多的CPU操作,可能会消耗更多的内存和存储空间,甚至还会影响索引的正常使用。不同的字符集和校对规则之间的转换可能会带来额外的系统开销。例如:排序查询要求的字符集与服务器数据的字符集相同的时候,才能使用索引进行排序。

    为了能够适应各种字符串,包括客户端字符集、在查询中显示指定的字符集,mysql会在需要的时候进行字符集转换。例如:当使用两个字符集不同的列来关联两个表的时候,mysql会尝试转换器中一个列的字符集。

    utf-8是一种多字节编码,它存储一个字符会使用变长的字节数(1~3字节)。在mysql内部,通常使用一个定长的空间来存储字符串,再进行相关操作,这样做的目的是希望总是保证缓存中有足够的空间来存储字符串。例如:一个编码是utf-8的char(10)需要30个字节,即使最终存储的时候没有存储任何”多字节“字符也是一样。变长的字段类型(varchar text)存储在磁盘上时不会有这个困扰,但当他存储在临时表中用来处理或者排序时,也总是会分配最大可能的长度。

    在多字节字符集中,一个字符不再是一个字节。索引,在msyql中有两个函数length()和char_length()来计算字符串的长度,在多字节字符集中,这两个函数的返回结果会不同。另外,在索引限制方面,如果要索引一个utf-8字符集的列,mysql会假设每一个字符都是三个字节,所以最长索引前缀的限制一下缩短到原来的三分之一了(最长索引限制为999字节,所以索引长度最大只能为333个字符了)。如果没有检查表的定义,可能不会注意到这仅仅在该列的前缀上建立了索引,这会对mysql使用索引有一些影响,例如无法使用索引覆盖扫描。

猜你喜欢

转载自student-lp.iteye.com/blog/2155038