mysql的字符集与排序规则

时间:2021-01-13 06:53:14

原文http://www.cnblogs.com/whiteyun/archive/2011/05/19/2051097.html

首先是show character set与show collation查看系统支持的字符集和排序规则;

mysql默认支持latin1字符集并且以latin_swedin_ci为排序规则;

binary和char binary的区别:

举个例子: create table testtype(col1 char(5), col2 binary(5)): 他们两个有什么区别呢?

insert into testtype values('aaaaa','aaaaa');

首先从存储上来说他们存储的值是一样的,都是将aaaaa转换成编码然后以二进制的形式存储的,这是计算机的基本原理,与数据类型无关;他们的不同是使用的时候不同,在使用col1做where 条件的时候,mysql是将存储在硬盘上的二进制按照column的字符集转换成对应的字符也就是'aaaaa',然后再按照排序与比较规则来确定哪些行需要返回; 例如对于latin_swedish_ci来说,他认为'a'和'A'是一样的,所以不管与col1比较的是'AAAAA或'aaaaa'都会返回这一行记录;而对于latin_swedish_cs排序和比较规则来看,'A和'a是不同的,所以这一行就不会返回; 而如果是使用latin_bin来比较呢? bin是以二进制来比较的,显然'a和''A的字符编码对应的二进制是不一样的,所以他们是不同的; 那么既然有了latin_swedian_cs为什么还要有latin_bin呢? _cs也是区分大小写的呀? 他们有什么不同的地方吗? 有,latin_swedian_cs是有字符集的,他们首先要将编码值转换成字符,再通过对应字符里定义的排序规则来比较;而_bin是直接使用二进制来比较的,它并不需要转换成字符集;

binary跟char也就是这种区别,binary跟char存储的时候其实是一样的,但是他在使用的时候同样是没有字符集的。所以它也是无字符集的binary comparision.

既然有binary那么为什么还要有_cs呢? 这还是那个问题,_cs是有字符集的,而_bin是没有的.

另外一个问题了, 对binary使用upper有用吗? 没有用,还是以上面那个表为例:

mysql>select upper(col1),upper(col2) from testtype;

+-------------+-------------+
| upper(col1) | upper(col2) |
+-------------+-------------+
| AAAAA       | aaaaa       |
+-------------+-------------+
1 row in set (0.05 sec)

注意collation影响的仅仅是排序和比较规则,但它对索引仍然会起到作用。因为索引是按照某种特定的排序规则而排列的。如果使用了不同的排序规则,而索引会用不上;

select * from testtype order by col1 collate utf8;

下面来讨论一下字符集的问题:

字符集是用来定义每个字符在系统里的编码的集合,因为所有的字符都是以编码值的形式存储在硬盘上的,所以当我们输入了字符之后系统一定需要将他们转换成编码值,然后再存储到硬盘上。那么MySQL是如何使用字符集的呢?

character_set_client, character_set_connection, character_set_database, character_set_server, character_set_result;让我们画个描述一下:

首先所有的字符都是放到某个应用程序中的,当应用程序执行的时候首先就会将字符转换成编码传输给其他应用程序,举个例子来说,web page会设置自己的字符集,当用户在page上输入了字符并且提交的时候首先page会把这个字符转换成编码,如果page的字符集是utf8, 那么就转换成utf8编码,这时候跟MySQL还没有发生任何关系,接着page需要把这些已经编码好的字符转给MySQL, 当MySQL接受到这个字符的时候它不知道这个字符集是什么编码的,可是它有character_set_client呀,这时候MySQL认为传来的那个字符集就是character_set_client设置的字符集,所以MySQL首先把这个字符集转换一下,那转换成什么字符集呢? 它就转换成character_set_connect设置的字符集。这时候mysql就以character_set_connection转换之后的字符在系统中运行,当它需要把数据存储到table里的时候,它还会发生再一次的转换.就是将字符按照character_set_connection字符集转换成column本身的字符集;

在取数据的时候是一个相反的过程,先将数据按照column自身的字符集转换成character_set_connection的字符集,然后再转换成character_set_result的字符集返回给应用程序,而应用程序拿到这个结果之后又将这个字符集转换成自己设置的字符集;

接着又来了其他问题,如果我们将character_set_server设置成latin1字符集,而页面要求使用utf8, 那该如何设置呢? 其实不难,执行set names latin1,那么页面首先会将数据按照utf8的编码转换,然后再将转换后的字符串发给mysql, 而mysql此时发现character_set_client, character_set_connection,character_set_server都是一样的,那么这中间就不会发生任何转换了。而在取数据的时候, 由于character_set_connection, character_set_result跟column自身的字符集也都是latin1,那也不会发生任何转换,而直接把数据取回到应用程序,应用程序使用自己设置的字符集utf8来显示数据,这时候也不会任何问题.

字符集对MySQL的影响:

不同的字符集不仅对DB的存储产生影响,还会影响MySQL里的一些其他变化:

1) 当mysql比较两个不同字符集的值时,它必须将它们转换为同一字符集,如果字符集不兼容,就会引发错误; Error 1267;

2) 对于utf8字符集,如果column的内容是ascii字符,那么同样只需要一个byte来保存,但是在索引的时候,使用的却是3个byte,而且在缓存里使用的也是3 bytes;

3) 使用不同字符集的两张表在关联的时候MySQL也需要字符集转换,这时候也不能使用索引;

至于在collation是使用_ci的好,还是_cs的好,现在还不清楚,觉得似乎无所谓。