MySQL 문자 집합 및 비교 규칙을 이해하도록 안내합니다.

WBOY
풀어 주다: 2022-01-20 16:58:22
앞으로
3198명이 탐색했습니다.

이 기사는 MySQL에서 지원되는 문자 세트 및 대조 규칙을 포함하여 MySQL의 문자 세트 비교에 대한 관련 지식을 제공합니다. 모든 사람에게 도움이 되기를 바랍니다.

MySQL 문자 집합 및 비교 규칙을 이해하도록 안내합니다.

문자 집합 소개 및 비교 규칙

문자 집합 소개

우리는 바이너리 데이터만 컴퓨터에 저장할 수 있다는 것을 알고 있는데 문자열을 어떻게 저장할까요? 물론 문자와 이진 데이터 간의 매핑 관계를 설정해야 합니다. 이 관계를 설정하려면 최소한 두 가지를 이해해야 합니다.

  1. 어떤 문자를 이진 데이터에 매핑하고 싶나요?

    즉, 문자 범위를 명확하게 정의하세요.

  2. 지도를 작성하는 방법은 무엇입니까?

    문자를 이진 데이터에 매핑하는 과정을 인코딩이라고도 하고, 이진 데이터를 문자에 매핑하는 과정을 디코딩이라고 합니다. 编码,将一个二进制数据映射到一个字符的过程叫做解码

人们抽象出一个字符集的概念来描述某个字符范围的编码规则。比方说我们来自定义一个名称为xiaohaizi的字符集,它包含的字符范围和编码规则如下:

  • 包含字符'a''b''A''B'

  • 编码规则如下:

    采用1个字节编码一个字符的形式,字符和字节的映射关系如下:

    'a' -> 00000001 (十六进制:0x01)
    'b' -> 00000010 (十六进制:0x02)
    'A' -> 00000011 (十六进制:0x03)
    'B' -> 00000100 (十六进制:0x04)
    로그인 후 복사

有了xiaohaizi字符集,我们就可以用二进制形式表示一些字符串了,下边是一些字符串用xiaohaizi字符集编码后的二进制表示:

'bA' -> 0000001000000011  (十六进制:0x0203)
'baB' -> 000000100000000100000100  (十六进制:0x020104)
'cd' -> 无法表示,字符集xiaohaizi不包含字符'c'和'd'
로그인 후 복사

比较规则简介

在我们确定了xiaohaizi字符集表示字符的范围以及编码规则后,怎么比较两个字符的大小呢?最容易想到的就是直接比较这两个字符对应的二进制编码的大小,比方说字符'a'的编码为0x01,字符'b'的编码为0x02,所以'a'小于'b',这种简单的比较规则也可以被称为二进制比较规则,英文名为binary collation

二进制比较规则是简单,但有时候并不符合现实需求,比如在很多场合对于英文字符我们都是不区分大小写的,也就是说'a''A'是相等的,在这种场合下就不能简单粗暴的使用二进制比较规则了,这时候我们可以这样指定比较规则:

  1. 将两个大小写不同的字符全都转为大写或者小写。
  2. 再比较这两个字符对应的二进制数据。

这是一种稍微复杂一点点的比较规则,但是实际生活中的字符不止英文字符一种,比如我们的汉字有几万之多,对于某一种字符集来说,比较两个字符大小的规则可以制定出很多种,也就是说同一种字符集可以有多种比较规则,我们稍后就要介绍各种现实生活中用的字符集以及它们的一些比较规则。

一些重要的字符集

不幸的是,这个世界太大了,不同的人制定出了好多种字符集,它们表示的字符范围和用到的编码规则可能都不一样。我们看一下一些常用字符集的情况:

  • ASCII字符集

    共收录128个字符,包括空格、标点符号、数字、大小写字母和一些不可见字符。由于总共才128个字符,所以可以使用1个字节来进行编码,我们看一些字符的编码方式:

    'L' ->  01001100(十六进制:0x4C,十进制:76)
    'M' ->  01001101(十六进制:0x4D,十进制:77)
    로그인 후 복사
  • ISO 8859-1字符集

    共收录256个字符,是在ASCII字符集的基础上又扩充了128个西欧常用字符(包括德法两国的字母),也可以使用1个字节来进行编码。这个字符集也有一个别名latin1

  • GB2312字符集

    收录了汉字以及拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母。其中收录汉字6763个,其他文字符号682个。同时这种字符集又兼容ASCII字符集,所以在编码方式上显得有些奇怪:

    • 如果该字符在ASCII字符集中,则采用1字节编码。
    • 否则采用2字节编码。

    这种表示一个字符需要的字节数可能不同的编码方式称为变长编码方式。比方说字符串'爱u',其中'爱'需要用2个字节进行编码,编码后的十六进制表示为0xB0AE'u'需要用1个字节进行编码,编码后的十六进制表示为0x75,所以拼合起来就是0xB0AE75

    小贴士:
    
    我们怎么区分某个字节代表一个单独的字符还是代表某个字符的一部分呢?别忘了`ASCII`字符集只收录128个字符,使用0~127就可以表示全部字符,所以如果某个字节是在0~127之内的,就意味着一个字节代表一个单独的字符,否则就是两个字节代表一个单独的字符。
    로그인 후 복사
  • GBK

    🎜사람들은 특정 문자 범위의 인코딩 규칙을 설명하기 위해 문자 세트의 개념을 추상화합니다. 예를 들어, xiaohaizi라는 문자 집합을 정의해 보겠습니다. 여기에 포함된 문자 범위와 인코딩 규칙은 다음과 같습니다. 🎜
      🎜🎜에는 'a' 문자가 포함되어 있습니다. 'b', 'A', 'B'. 🎜🎜🎜🎜인코딩 규칙은 다음과 같습니다. 🎜🎜1바이트를 사용하여 한 문자를 인코딩합니다. 문자와 바이트 간의 매핑 관계는 다음과 같습니다. 🎜
    'L' ->  01001100(十六进制:0x4C)
    '啊' ->  111001011001010110001010(十六进制:0xE5958A)
    로그인 후 복사
    로그인 후 복사
    🎜
🎜 xiaohaizi 문자 집합을 사용하면 일부 문자열을 이진 형식으로 표현할 수 있습니다. 다음은 xiaohaizi 문자 집합으로 인코딩된 일부 문자열의 이진 표현입니다. 🎜
小贴士:

其实准确的说,utf8只是Unicode字符集的一种编码方案,Unicode字符集可以采用utf8、utf16、utf32这几种编码方案,utf8使用1~4个字节编码一个字符,utf16使用2个或4个字节编码一个字符,utf32使用4个字节编码一个字符。更详细的Unicode和其编码方案的知识不是本书的重点,大家上网查查哈~

MySQL中并不区分字符集和编码方案的概念,所以后边唠叨的时候把utf8、utf16、utf32都当作一种字符集对待。
로그인 후 복사
로그인 후 복사

비교 규칙 소개

🎜 xiaohaizi 문자 세트가 나타내는 문자 범위와 인코딩 규칙을 결정한 후 두 문자의 크기를 어떻게 비교합니까? 가장 쉽게 생각하는 것은 두 문자에 해당하는 바이너리 코드의 크기를 직접 비교하는 것이다. 예를 들어 'a' 문자의 코드는 0x01이고, 문자 'b'의 코드 의 인코딩은 0x02이므로 'a''b'. 이 간단한 비교 규칙은 이진 비교 규칙이라고도 하며 영어 이름은 <code>binary collation입니다. 🎜🎜이진 비교 규칙은 간단하지만 때로는 실제 요구 사항을 충족하지 못하는 경우가 있습니다. 예를 들어 많은 경우 영어 문자, 즉 'a'의 경우 대소문자를 구분하지 않습니다. 'A'는 동일합니다. 이 경우 이진 비교 규칙을 간단하고 대략적으로 사용할 수는 없습니다. 이때는 다음과 같이 비교 규칙을 지정할 수 있습니다. 🎜🎜🎜두 문자를 모두 다른 대문자와 소문자로 변환합니다. 대문자 또는 소문자로. 🎜🎜이 두 문자에 해당하는 이진 데이터를 비교하세요. 🎜🎜이것은 조금 더 복잡한 비교 규칙이지만 실제 생활에는 영어 문자 이상의 것이 있습니다. 예를 들어 특정 문자 집합에 대해 비교 문자에는 여러 가지가 있습니다. 즉, 동일한 문자 집합이 여러 개의 비교 규칙을 가질 수 있음을 의미합니다. 실제 생활에서 사용되는 다양한 문자 집합과 그에 대한 비교 규칙 중 일부를 나중에 소개하겠습니다. 🎜

몇 가지 중요한 문자 세트

🎜안타깝게도 세상은 너무 넓고 다양한 사람들이 다양한 문자 세트를 개발했습니다. 사용되는 인코딩 규칙은 다를 수 있습니다. 일반적으로 사용되는 문자 집합을 살펴보겠습니다. 🎜
    🎜🎜ASCII 문자 집합 🎜🎜에는 공백, 문장 부호, 숫자, 대문자 및 소문자 및 문자를 포함하여 총 128자가 포함됩니다. 일부 보이지 않는 문자. 총 128자만 있으므로 인코딩에 1바이트를 사용할 수 있습니다. 일부 문자의 인코딩 방법을 살펴보겠습니다. 🎜
utf8编码:111001101000100010010001 (3个字节,十六进制表示是:0xE68891)
gb2312编码:1011000010101110 (2个字节,十六进制表示是:0xB0AE)
로그인 후 복사
로그인 후 복사
🎜🎜🎜ISO 8859-1 문자 세트 🎜🎜에는 총 128자가 포함됩니다. 256자 문자는 ASCII 문자 세트를 기반으로 하며 일반적으로 사용되는 128개의 서유럽 문자(독일 및 프랑스 문자 포함)로 확장됩니다. 또한 1바이트를 사용하여 인코딩할 수도 있습니다. 이 문자 집합에는 latin1 별칭도 있습니다. 🎜🎜🎜🎜GB2312 문자 세트🎜🎜에는 한자뿐만 아니라 라틴 문자, 그리스 문자, 일본어 히라가나 및 가타카나 문자, 러시아어 키릴 문자도 포함됩니다. 6763개의 한자와 682개의 기타 문자가 포함되어 있습니다. 동시에 이 문자 세트는 ASCII 문자 세트와 호환되므로 인코딩 방법이 약간 이상해 보입니다. 🎜
    🎜문자가 ASCII에 있는 경우 > 문자 집합에는 1바이트 인코딩을 사용합니다. 🎜🎜그렇지 않으면 2바이트 인코딩이 사용됩니다. 🎜
🎜한 문자에 필요한 바이트 수가 다를 수 있음을 나타내는 이러한 인코딩 방식을 가변 길이 인코딩 방식이라고 합니다. 예를 들어, '爱'가 2바이트로 인코딩되어야 하는 문자열 '爱u', 인코딩된 16진수 표현은 0xB0AE입니다. <code>'u'는 1바이트로 인코딩되어야 하며 인코딩된 16진수 표현은 0x75이므로 합치면 0xB0AE75가 됩니다. 🎜
SHOW (CHARACTER SET|CHARSET) [LIKE 匹配的模式];
로그인 후 복사
로그인 후 복사
🎜🎜🎜GBK 문자 집합🎜

GBK字符集只是在收录字符范围上对GB2312字符集作了扩充,编码方式上兼容GB2312

  • utf8字符集

    收录地球上能想到的所有字符,而且还在不断扩充。这种字符集兼容ASCII字符集,采用变长编码方式,编码一个字符需要使用1~4个字节,比方说这样:

    'L' ->  01001100(十六进制:0x4C)
    '啊' ->  111001011001010110001010(十六进制:0xE5958A)
    로그인 후 복사
    로그인 후 복사
    小贴士:
    
    其实准确的说,utf8只是Unicode字符集的一种编码方案,Unicode字符集可以采用utf8、utf16、utf32这几种编码方案,utf8使用1~4个字节编码一个字符,utf16使用2个或4个字节编码一个字符,utf32使用4个字节编码一个字符。更详细的Unicode和其编码方案的知识不是本书的重点,大家上网查查哈~
    
    MySQL中并不区分字符集和编码方案的概念,所以后边唠叨的时候把utf8、utf16、utf32都当作一种字符集对待。
    로그인 후 복사
    로그인 후 복사
  • 对于同一个字符,不同字符集也可能有不同的编码方式。比如对于汉字'我'来说,ASCII字符集中根本没有收录这个字符,utf8gb2312字符集对汉字的编码方式如下:

    utf8编码:111001101000100010010001 (3个字节,十六进制表示是:0xE68891)
    gb2312编码:1011000010101110 (2个字节,十六进制表示是:0xB0AE)
    로그인 후 복사
    로그인 후 복사

    MySQL中支持的字符集和排序规则

    MySQL中的utf8和utf8mb4

    我们上边说utf8字符集表示一个字符需要使用1~4个字节,但是我们常用的一些字符使用1~3个字节就可以表示了。而在MySQL中字符集表示一个字符所用最大字节长度在某些方面会影响系统的存储和性能,所以设计MySQL的大叔偷偷的定义了两个概念:

    • utf8mb3:阉割过的utf8字符集,只使用1~3个字节表示字符。

    • utf8mb4:正宗的utf8字符集,使用1~4个字节表示字符。

    有一点需要大家十分的注意,在MySQLutf8utf8mb3的别名,所以之后在MySQL中提到utf8就意味着使用1~3个字节来表示一个字符,如果大家有使用4字节编码一个字符的情况,比如存储一些emoji表情啥的,那请使用utf8mb4

    字符集的查看

    MySQL支持好多好多种字符集,查看当前MySQL中支持的字符集可以用下边这个语句:

    SHOW (CHARACTER SET|CHARSET) [LIKE 匹配的模式];
    로그인 후 복사
    로그인 후 복사

    其中CHARACTER SETCHARSET是同义词,用任意一个都可以。我们查询一下(支持的字符集太多了,我们省略了一些):

    mysql> SHOW CHARSET;
    +----------+---------------------------------+---------------------+--------+
    | Charset  | Description                     | Default collation   | Maxlen |
    +----------+---------------------------------+---------------------+--------+
    | big5     | Big5 Traditional Chinese        | big5_chinese_ci     |      2 |
    ...
    | latin1   | cp1252 West European            | latin1_swedish_ci   |      1 |
    | latin2   | ISO 8859-2 Central European     | latin2_general_ci   |      1 |
    ...
    | ascii    | US ASCII                        | ascii_general_ci    |      1 |
    ...
    | gb2312   | GB2312 Simplified Chinese       | gb2312_chinese_ci   |      2 |
    ...
    | gbk      | GBK Simplified Chinese          | gbk_chinese_ci      |      2 |
    | latin5   | ISO 8859-9 Turkish              | latin5_turkish_ci   |      1 |
    ...
    | utf8     | UTF-8 Unicode                   | utf8_general_ci     |      3 |
    | ucs2     | UCS-2 Unicode                   | ucs2_general_ci     |      2 |
    ...
    | latin7   | ISO 8859-13 Baltic              | latin7_general_ci   |      1 |
    | utf8mb4  | UTF-8 Unicode                   | utf8mb4_general_ci  |      4 |
    | utf16    | UTF-16 Unicode                  | utf16_general_ci    |      4 |
    | utf16le  | UTF-16LE Unicode                | utf16le_general_ci  |      4 |
    ...
    | utf32    | UTF-32 Unicode                  | utf32_general_ci    |      4 |
    | binary   | Binary pseudo charset           | binary              |      1 |
    ...
    | gb18030  | China National Standard GB18030 | gb18030_chinese_ci  |      4 |
    +----------+---------------------------------+---------------------+--------+
    41 rows in set (0.01 sec)
    로그인 후 복사

    可以看到,我使用的这个MySQL版本一共支持41种字符集,其中的Default collation列表示这种字符集中一种默认的比较规则。大家注意返回结果中的最后一列Maxlen,它代表该种字符集表示一个字符最多需要几个字节。为了让大家的印象更深刻,我把几个常用到的字符集的Maxlen列摘抄下来,大家务必记住:

    字符集名称 Maxlen
    ascii 1
    latin1 1
    gb2312 2
    gbk 2
    utf8 3
    utf8mb4 4

    比较规则的查看

    查看MySQL中支持的比较规则的命令如下:

    SHOW COLLATION [LIKE 匹配的模式];
    로그인 후 복사

    我们前边说过一种字符集可能对应着若干种比较规则,MySQL支持的字符集就已经非常多了,所以支持的比较规则更多,我们先只查看一下utf8字符集下的比较规则:

    mysql> SHOW COLLATION LIKE 'utf8\_%';
    +--------------------------+---------+-----+---------+----------+---------+
    | Collation                | Charset | Id  | Default | Compiled | Sortlen |
    +--------------------------+---------+-----+---------+----------+---------+
    | utf8_general_ci          | utf8    |  33 | Yes     | Yes      |       1 |
    | utf8_bin                 | utf8    |  83 |         | Yes      |       1 |
    | utf8_unicode_ci          | utf8    | 192 |         | Yes      |       8 |
    | utf8_icelandic_ci        | utf8    | 193 |         | Yes      |       8 |
    | utf8_latvian_ci          | utf8    | 194 |         | Yes      |       8 |
    | utf8_romanian_ci         | utf8    | 195 |         | Yes      |       8 |
    | utf8_slovenian_ci        | utf8    | 196 |         | Yes      |       8 |
    | utf8_polish_ci           | utf8    | 197 |         | Yes      |       8 |
    | utf8_estonian_ci         | utf8    | 198 |         | Yes      |       8 |
    | utf8_spanish_ci          | utf8    | 199 |         | Yes      |       8 |
    | utf8_swedish_ci          | utf8    | 200 |         | Yes      |       8 |
    | utf8_turkish_ci          | utf8    | 201 |         | Yes      |       8 |
    | utf8_czech_ci            | utf8    | 202 |         | Yes      |       8 |
    | utf8_danish_ci           | utf8    | 203 |         | Yes      |       8 |
    | utf8_lithuanian_ci       | utf8    | 204 |         | Yes      |       8 |
    | utf8_slovak_ci           | utf8    | 205 |         | Yes      |       8 |
    | utf8_spanish2_ci         | utf8    | 206 |         | Yes      |       8 |
    | utf8_roman_ci            | utf8    | 207 |         | Yes      |       8 |
    | utf8_persian_ci          | utf8    | 208 |         | Yes      |       8 |
    | utf8_esperanto_ci        | utf8    | 209 |         | Yes      |       8 |
    | utf8_hungarian_ci        | utf8    | 210 |         | Yes      |       8 |
    | utf8_sinhala_ci          | utf8    | 211 |         | Yes      |       8 |
    | utf8_german2_ci          | utf8    | 212 |         | Yes      |       8 |
    | utf8_croatian_ci         | utf8    | 213 |         | Yes      |       8 |
    | utf8_unicode_520_ci      | utf8    | 214 |         | Yes      |       8 |
    | utf8_vietnamese_ci       | utf8    | 215 |         | Yes      |       8 |
    | utf8_general_mysql500_ci | utf8    | 223 |         | Yes      |       1 |
    +--------------------------+---------+-----+---------+----------+---------+
    27 rows in set (0.00 sec)
    로그인 후 복사

    这些比较规则的命名还挺有规律的,具体规律如下:

    • 比较规则名称以与其关联的字符集的名称开头。如上图的查询结果的比较规则名称都是以utf8开头的。

    • 后边紧跟着该比较规则主要作用于哪种语言,比如utf8_polish_ci表示以波兰语的规则比较,utf8_spanish_ci是以西班牙语的规则比较,utf8_general_ci是一种通用的比较规则。

    • 名称后缀意味着该比较规则是否区分语言中的重音、大小写啥的,具体可以用的值如下:

      后缀 英文释义 描述
      _ai accent insensitive 不区分重音
      _as accent sensitive 区分重音
      _ci case insensitive 不区分大小写
      _cs case sensitive 区分大小写
      _bin binary 以二进制方式比较

      比如utf8_general_ci这个比较规则是以ci结尾的,说明不区分大小写。

    每种字符集对应若干种比较规则,每种字符集都有一种默认的比较规则,SHOW COLLATION的返回结果中的Default列的值为YES的就是该字符集的默认比较规则,比方说utf8字符集默认的比较规则就是utf8_general_ci

    字符集和比较规则的应用

    各级别的字符集和比较规则

    MySQL有4个级别的字符集和比较规则,分别是:

    • 服务器级别
    • 数据库级别
    • 表级别
    • 列级别

    我们接下来仔细看一下怎么设置和查看这几个级别的字符集和比较规则。

    服务器级别

    MySQL提供了两个系统变量来表示服务器级别的字符集和比较规则:

    系统变量 描述
    character_set_server 服务器级别的字符集
    collation_server 服务器级别的比较规则

    我们看一下这两个系统变量的值:

    mysql> SHOW VARIABLES LIKE 'character_set_server';
    +----------------------+-------+
    | Variable_name        | Value |
    +----------------------+-------+
    | character_set_server | utf8  |
    +----------------------+-------+
    1 row in set (0.00 sec)
    
    mysql> SHOW VARIABLES LIKE 'collation_server';
    +------------------+-----------------+
    | Variable_name    | Value           |
    +------------------+-----------------+
    | collation_server | utf8_general_ci |
    +------------------+-----------------+
    1 row in set (0.00 sec)
    로그인 후 복사

    可以看到在我的计算机中服务器级别默认的字符集是utf8,默认的比较规则是utf8_general_ci

    我们可以在启动服务器程序时通过启动选项或者在服务器程序运行过程中使用SET语句修改这两个变量的值。比如我们可以在配置文件中这样写:

    [server]
    character_set_server=gbk
    collation_server=gbk_chinese_ci
    로그인 후 복사

    当服务器启动的时候读取这个配置文件后这两个系统变量的值便修改了。

    数据库级别

    我们在创建和修改数据库的时候可以指定该数据库的字符集和比较规则,具体语法如下:

    CREATE DATABASE 数据库名
        [[DEFAULT] CHARACTER SET 字符集名称]
        [[DEFAULT] COLLATE 比较规则名称];
    
    ALTER DATABASE 数据库名
        [[DEFAULT] CHARACTER SET 字符集名称]
        [[DEFAULT] COLLATE 比较规则名称];
    로그인 후 복사
    로그인 후 복사

    其中的DEFAULT可以省略,并不影响语句的语义。比方说我们新创建一个名叫charset_demo_db的数据库,在创建的时候指定它使用的字符集为gb2312,比较规则为gb2312_chinese_ci

    mysql> CREATE DATABASE charset_demo_db
        -> CHARACTER SET gb2312
        -> COLLATE gb2312_chinese_ci;
    Query OK, 1 row affected (0.01 sec)
    로그인 후 복사

    如果想查看当前数据库使用的字符集和比较规则,可以查看下面两个系统变量的值(前提是使用USE语句选择当前默认数据库,如果没有默认数据库,则变量与相应的服务器级系统变量具有相同的值):

    系统变量 描述
    character_set_database 当前数据库的字符集
    collation_database 当前数据库的比较规则

    我们来查看一下刚刚创建的charset_demo_db数据库的字符集和比较规则:

    mysql> USE charset_demo_db;
    Database changed
    
    mysql> SHOW VARIABLES LIKE 'character_set_database';
    +------------------------+--------+
    | Variable_name          | Value  |
    +------------------------+--------+
    | character_set_database | gb2312 |
    +------------------------+--------+
    1 row in set (0.00 sec)
    
    mysql> SHOW VARIABLES LIKE 'collation_database';
    +--------------------+-------------------+
    | Variable_name      | Value             |
    +--------------------+-------------------+
    | collation_database | gb2312_chinese_ci |
    +--------------------+-------------------+
    1 row in set (0.00 sec)
    
    mysql>
    로그인 후 복사

    可以看到这个charset_demo_db数据库的字符集和比较规则就是我们在创建语句中指定的。需要注意的一点是: character_set_database 和 collation_database 这两个系统变量是只读的,我们不能通过修改这两个变量的值而改变当前数据库的字符集和比较规则。

    数据库的创建语句中也可以不指定字符集和比较规则,比如这样:

    CREATE DATABASE 数据库名;
    로그인 후 복사

    这样的话将使用服务器级别的字符集和比较规则作为数据库的字符集和比较规则。

    表级别

    我们也可以在创建和修改表的时候指定表的字符集和比较规则,语法如下:

    CREATE TABLE 表名 (列的信息)
        [[DEFAULT] CHARACTER SET 字符集名称]
        [COLLATE 比较规则名称]]
    
    ALTER TABLE 表名
        [[DEFAULT] CHARACTER SET 字符集名称]
        [COLLATE 比较规则名称]
    로그인 후 복사

    比方说我们在刚刚创建的charset_demo_db数据库中创建一个名为t的表,并指定这个表的字符集和比较规则:

    mysql> CREATE TABLE t(
        ->     col VARCHAR(10)
        -> ) CHARACTER SET utf8 COLLATE utf8_general_ci;
    Query OK, 0 rows affected (0.03 sec)
    로그인 후 복사

    如果创建和修改表的语句中没有指明字符集和比较规则,将使用该表所在数据库的字符集和比较规则作为该表的字符集和比较规则。假设我们的创建表t的语句是这么写的:

    CREATE TABLE t(
        col VARCHAR(10)
    );
    로그인 후 복사

    因为表t的建表语句中并没有明确指定字符集和比较规则,则表t的字符集和比较规则将继承所在数据库charset_demo_db的字符集和比较规则,也就是gb2312gb2312_chinese_ci

    列级别

    需要注意的是,对于存储字符串的列,同一个表中的不同的列也可以有不同的字符集和比较规则。我们在创建和修改列定义的时候可以指定该列的字符集和比较规则,语法如下:

    CREATE TABLE 表名(
        列名 字符串类型 [CHARACTER SET 字符集名称] [COLLATE 比较规则名称],
        其他列...
    );
    
    ALTER TABLE 表名 MODIFY 列名 字符串类型 [CHARACTER SET 字符集名称] [COLLATE 比较规则名称];
    로그인 후 복사
    로그인 후 복사

    比如我们修改一下表t中列col的字符集和比较规则可以这么写:

    mysql> ALTER TABLE t MODIFY col VARCHAR(10) CHARACTER SET gbk COLLATE gbk_chinese_ci;
    Query OK, 0 rows affected (0.04 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    mysql>
    로그인 후 복사

    对于某个列来说,如果在创建和修改的语句中没有指明字符集和比较规则,将使用该列所在表的字符集和比较规则作为该列的字符集和比较规则。比方说表t的字符集是utf8,比较规则是utf8_general_ci,修改列col的语句是这么写的:

    ALTER TABLE t MODIFY col VARCHAR(10);
    로그인 후 복사

    那列col的字符集和编码将使用表t的字符集和比较规则,也就是utf8utf8_general_ci

    小贴士

    在转换列的字符集时需要注意,如果转换前列中存储的数据不能用转换后的字符集进行表示会发生错误。比方说原先列使用的字符集是utf8,列中存储了一些汉字,现在把列的字符集转换为ascii的话就会出错,因为ascii字符集并不能表示汉字字符。

    仅修改字符集或仅修改比较规则

    由于字符集和比较规则是互相有联系的,如果我们只修改了字符集,比较规则也会跟着变化,如果只修改了比较规则,字符集也会跟着变化,具体规则如下:

    • 只修改字符集,则比较规则将变为修改后的字符集默认的比较规则。
    • 只修改比较规则,则字符集将变为修改后的比较规则对应的字符集。

    不论哪个级别的字符集和比较规则,这两条规则都适用,我们以服务器级别的字符集和比较规则为例来看一下详细过程:

    • 只修改字符集,则比较规则将变为修改后的字符集默认的比较规则。

      mysql> SET character_set_server = gb2312;
      Query OK, 0 rows affected (0.00 sec)
      
      mysql> SHOW VARIABLES LIKE 'character_set_server';
      +----------------------+--------+
      | Variable_name        | Value  |
      +----------------------+--------+
      | character_set_server | gb2312 |
      +----------------------+--------+
      1 row in set (0.00 sec)
      
      mysql>  SHOW VARIABLES LIKE 'collation_server';
      +------------------+-------------------+
      | Variable_name    | Value             |
      +------------------+-------------------+
      | collation_server | gb2312_chinese_ci |
      +------------------+-------------------+
      1 row in set (0.00 sec)
      로그인 후 복사

      我们只修改了character_set_server的值为gb2312collation_server的值自动变为了gb2312_chinese_ci

    • 只修改比较规则,则字符集将变为修改后的比较规则对应的字符集。

      mysql> SET collation_server = utf8_general_ci;
      Query OK, 0 rows affected (0.00 sec)
      
      mysql> SHOW VARIABLES LIKE 'character_set_server';
      +----------------------+-------+
      | Variable_name        | Value |
      +----------------------+-------+
      | character_set_server | utf8  |
      +----------------------+-------+
      1 row in set (0.00 sec)
      
      mysql> SHOW VARIABLES LIKE 'collation_server';
      +------------------+-----------------+
      | Variable_name    | Value           |
      +------------------+-----------------+
      | collation_server | utf8_general_ci |
      +------------------+-----------------+
      1 row in set (0.00 sec)
      
      mysql>
      로그인 후 복사

      我们只修改了collation_server的值为utf8_general_cicharacter_set_server的值自动变为了utf8

    各级别字符集和比较规则小结

    我们介绍的这4个级别字符集和比较规则的联系如下:

    • 如果创建或修改列时没有显式的指定字符集和比较规则,则该列默认用表的字符集和比较规则
    • 如果创建表时没有显式的指定字符集和比较规则,则该表默认用数据库的字符集和比较规则
    • 如果创建数据库时没有显式的指定字符集和比较规则,则该数据库默认用服务器的字符集和比较规则

    知道了这些规则之后,对于给定的表,我们应该知道它的各个列的字符集和比较规则是什么,从而根据这个列的类型来确定存储数据时每个列的实际数据占用的存储空间大小了。比方说我们向表t中插入一条记录:

    mysql> INSERT INTO t(col) VALUES('我我');
    Query OK, 1 row affected (0.00 sec)
    
    mysql> SELECT * FROM t;
    +--------+
    | s      |
    +--------+
    | 我我   |
    +--------+
    1 row in set (0.00 sec)
    로그인 후 복사

    首先列col使用的字符集是gbk,一个字符'我'gbk中的编码为0xCED2,占用两个字节,两个字符的实际数据就占用4个字节。如果把该列的字符集修改为utf8的话,这两个字符就实际占用6个字节啦~

    客户端和服务器通信中的字符集

    编码和解码使用的字符集不一致的后果

    说到底,字符串在计算机上的体现就是一个字节串,如果你使用不同字符集去解码这个字节串,最后得到的结果可能让你挠头。

    我们知道字符'我'utf8字符集编码下的字节串长这样:0xE68891,如果一个程序把这个字节串发送到另一个程序里,另一个程序用不同的字符集去解码这个字节串,假设使用的是gbk字符集来解释这串字节,解码过程就是这样的:

    1. 首先看第一个字节0xE6,它的值大于0x7F(十进制:127),说明是两字节编码,继续读一字节后是0xE688,然后从gbk编码表中查找字节为0xE688对应的字符,发现是字符'鎴'

    2. 继续读一个字节0x91,它的值也大于0x7F,再往后读一个字节发现木有了,所以这是半个字符。

    3. 所以0xE68891gbk字符集解释成一个字符'鎴'和半个字符。

    假设用iso-8859-1,也就是latin1字符集去解释这串字节,解码过程如下:

    1. 先读第一个字节0xE6,它对应的latin1字符为æ

    2. 再读第二个字节0x88,它对应的latin1字符为ˆ

    3. 再读第三个字节0x91,它对应的latin1字符为

    4. 所以整串字节0xE68891latin1字符集解释后的字符串就是'我'

    可见,如果对于同一个字符串编码和解码使用的字符集不一样,会产生意想不到的结果,作为人类的我们看上去就像是产生了乱码一样。

    字符集转换的概念

    如果接收0xE68891这个字节串的程序按照utf8字符集进行解码,然后又把它按照gbk字符集进行编码,最后编码后的字节串就是0xCED2,我们把这个过程称为字符集的转换,也就是字符串'我'utf8字符集转换为gbk字符集。

    MySQL中字符集的转换

    我们知道从客户端发往服务器的请求本质上就是一个字符串,服务器向客户端返回的结果本质上也是一个字符串,而字符串其实是使用某种字符集编码的二进制数据。这个字符串可不是使用一种字符集的编码方式一条道走到黑的,从发送请求到返回结果这个过程中伴随着多次字符集的转换,在这个过程中会用到3个系统变量,我们先把它们写出来看一下:

    系统变量 描述
    character_set_client 服务器解码请求时使用的字符集
    character_set_connection 服务器处理请求时会把请求字符串从character_set_client转为character_set_connection
    character_set_results 服务器向客户端返回数据时使用的字符集

    这几个系统变量在我的计算机上的默认值如下(不同操作系统的默认值可能不同):

    mysql> SHOW VARIABLES LIKE 'character_set_client';
    +----------------------+-------+
    | Variable_name        | Value |
    +----------------------+-------+
    | character_set_client | utf8  |
    +----------------------+-------+
    1 row in set (0.00 sec)
    
    mysql> SHOW VARIABLES LIKE 'character_set_connection';
    +--------------------------+-------+
    | Variable_name            | Value |
    +--------------------------+-------+
    | character_set_connection | utf8  |
    +--------------------------+-------+
    1 row in set (0.01 sec)
    
    mysql> SHOW VARIABLES LIKE 'character_set_results';
    +-----------------------+-------+
    | Variable_name         | Value |
    +-----------------------+-------+
    | character_set_results | utf8  |
    +-----------------------+-------+
    1 row in set (0.00 sec)
    로그인 후 복사

    大家可以看到这几个系统变量的值都是utf8,为了体现出字符集在请求处理过程中的变化,我们这里特意修改一个系统变量的值:

    mysql> set character_set_connection = gbk;
    Query OK, 0 rows affected (0.00 sec)
    로그인 후 복사

    所以现在系统变量character_set_clientcharacter_set_results的值还是utf8,而character_set_connection的值为gbk。现在假设我们客户端发送的请求是下边这个字符串:

    SELECT * FROM t WHERE s = '我';
    로그인 후 복사

    为了方便大家理解这个过程,我们只分析字符'我'在这个过程中字符集的转换。

    现在看一下在请求从发送到结果返回过程中字符集的变化:

    1. 客户端发送请求所使用的字符集

      一般情况下客户端所使用的字符集和当前操作系统一致,不同操作系统使用的字符集可能不一样,如下:

      • Unix系统使用的是utf8
      • Windows使用的是gbk

      例如我在使用的macOS操作系统时,客户端使用的就是utf8字符集。所以字符'我'在发送给服务器的请求中的字节形式就是:0xE68891

      小贴士:
      
      如果你使用的是可视化工具,比如navicat之类的,这些工具可能会使用自定义的字符集来编码发送到服务器的字符串,而不采用操作系统默认的字符集(所以在学习的时候还是尽量用黑框框哈)。
      로그인 후 복사
    2. 服务器接收到客户端发送来的请求其实是一串二进制的字节,它会认为这串字节采用的字符集是character_set_client,然后把这串字节转换为character_set_connection字符集编码的字符。

      由于我的计算机上character_set_client的值是utf8,首先会按照utf8字符集对字节串0xE68891进行解码,得到的字符串就是'我',然后按照character_set_connection代表的字符集,也就是gbk进行编码,得到的结果就是字节串0xCED2

    3. 因为表t的列col采用的是gbk字符集,与character_set_connection一致,所以直接到列中找字节值为0xCED2的记录,最后找到了一条记录。

      小贴士:
      
      如果某个列使用的字符集和character_set_connection代表的字符集不一致的话,还需要进行一次字符集转换。
      로그인 후 복사
    4. 上一步骤找到的记录中的col列其实是一个字节串0xCED2col列是采用gbk进行编码的,所以首先会将这个字节串使用gbk进行解码,得到字符串'我',然后再把这个字符串使用character_set_results代表的字符集,也就是utf8进行编码,得到了新的字节串:0xE68891,然后发送给客户端。

    5. 由于客户端是用的字符集是utf8,所以可以顺利的将0xE68891解释成字符,从而显示到我们的显示器上,所以我们人类也读懂了返回的结果。

    如果你读上边的文字有点晕,可以参照这个图来仔细分析一下这几个步骤:

    MySQL 문자 집합 및 비교 규칙을 이해하도록 안내합니다.

    从这个分析中我们可以得出这么几点需要注意的地方:

    • 服务器认为客户端发送过来的请求是用character_set_client编码的。

      假设你的客户端采用的字符集和 character_set_client 不一样的话,这就会出现意想不到的情况。比如我的客户端使用的是utf8字符集,如果把系统变量character_set_client的值设置为ascii的话,服务器可能无法理解我们发送的请求,更别谈处理这个请求了。

    • 服务器将把得到的结果集使用character_set_results编码后发送给客户端。

      假设你的客户端采用的字符集和 character_set_results 不一样的话,这就可能会出现客户端无法解码结果集的情况,结果就是在你的屏幕上出现乱码。比如我的客户端使用的是utf8字符集,如果把系统变量character_set_results的值设置为ascii的话,可能会产生乱码。

    • character_set_connection只是服务器在将请求的字节串从character_set_client转换为character_set_connection时使用,它是什么其实没多重要,但是一定要注意,该字符集包含的字符范围一定涵盖请求中的字符,要不然会导致有的字符无法使用character_set_connection代表的字符集进行编码。比如你把character_set_client设置为utf8,把character_set_connection设置成ascii,那么此时你如果从客户端发送一个汉字到服务器,那么服务器无法使用ascii字符集来编码这个汉字,就会向用户发出一个警告。

    知道了在MySQL中从发送请求到返回结果过程里发生的各种字符集转换,但是为啥要转来转去的呢?不晕么?

    答:是的,很头晕,所以我们通常都把 character_set_client 、character_set_connectioncharacter_set_results 这三个系统变量设置成和客户端使用的字符集一致的情况,这样减少了很多无谓的字符集转换。为了方便我们设置,MySQL提供了一条非常简便的语句:

    SET NAMES 字符集名;
    로그인 후 복사

    这一条语句产生的效果和我们执行这3条的效果是一样的:

    SET character_set_client = 字符集名;
    SET character_set_connection = 字符集名;
    SET character_set_results = 字符集名;
    로그인 후 복사

    比方说我的客户端使用的是utf8字符集,所以需要把这几个系统变量的值都设置为utf8

    mysql> SET NAMES utf8;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SHOW VARIABLES LIKE 'character_set_client';
    +----------------------+-------+
    | Variable_name        | Value |
    +----------------------+-------+
    | character_set_client | utf8  |
    +----------------------+-------+
    1 row in set (0.00 sec)
    
    mysql>  SHOW VARIABLES LIKE 'character_set_connection';
    +--------------------------+-------+
    | Variable_name            | Value |
    +--------------------------+-------+
    | character_set_connection | utf8  |
    +--------------------------+-------+
    1 row in set (0.00 sec)
    
    mysql> SHOW VARIABLES LIKE 'character_set_results';
    +-----------------------+-------+
    | Variable_name         | Value |
    +-----------------------+-------+
    | character_set_results | utf8  |
    +-----------------------+-------+
    1 row in set (0.00 sec)
    
    mysql>
    로그인 후 복사

    另外,如果你想在启动客户端的时候就把character_set_clientcharacter_set_connectioncharacter_set_results这三个系统变量的值设置成一样的,那我们可以在启动客户端的时候指定一个叫default-character-set的启动选项,比如在配置文件里可以这么写:

    [client]
    default-character-set=utf8
    로그인 후 복사

    它起到的效果和执行一遍SET NAMES utf8是一样一样的,都会将那三个系统变量的值设置成utf8

    比较规则的应用

    结束了字符集的漫游,我们把视角再次聚焦到比较规则比较规则的作用通常体现比较字符串大小的表达式以及对某个字符串列进行排序中,所以有时候也称为排序规则。比方说表t的列col使用的字符集是gbk,使用的比较规则是gbk_chinese_ci,我们向里边插入几条记录:

    mysql> INSERT INTO t(col) VALUES('a'), ('b'), ('A'), ('B');
    Query OK, 4 rows affected (0.00 sec)
    Records: 4  Duplicates: 0  Warnings: 0
    
    mysql>
    로그인 후 복사

    我们查询的时候按照t列排序一下:

    mysql> SELECT * FROM t ORDER BY col;
    +------+
    | col  |
    +------+
    | a    |
    | A    |
    | b    |
    | B    |
    | 我   |
    +------+
    5 rows in set (0.00 sec)
    로그인 후 복사

    可以看到在默认的比较规则gbk_chinese_ci中是不区分大小写的,我们现在把列col的比较规则修改为gbk_bin

    mysql> ALTER TABLE t MODIFY col VARCHAR(10) COLLATE gbk_bin;
    Query OK, 5 rows affected (0.02 sec)
    Records: 5  Duplicates: 0  Warnings: 0
    로그인 후 복사

    由于gbk_bin是直接比较字符的编码,所以是区分大小写的,我们再看一下排序后的查询结果:

    mysql> SELECT * FROM t ORDER BY s;
    +------+
    | s    |
    +------+
    | A    |
    | B    |
    | a    |
    | b    |
    | 我   |
    +------+
    5 rows in set (0.00 sec)
    
    mysql>
    로그인 후 복사

    所以如果以后大家在对字符串做比较或者对某个字符串列做排序操作时没有得到想象中的结果,需要思考一下是不是比较规则的问题~

    小贴士:
    
    列`col`中各个字符在使用gbk字符集编码后对应的数字如下:
    'A' -> 65 (十进制)
    'B' -> 66 (十进制)
    'a' -> 97 (十进制)
    'b' -> 98 (十进制)
    '我' -> 25105 (十进制)
    로그인 후 복사

    总结

    1. 字符集指的是某个字符范围的编码规则。

    2. 比较规则是针对某个字符集中的字符比较大小的一种规则。

    3. MySQL中,一个字符集可以有若干种比较规则,其中有一个默认的比较规则,一个比较规则必须对应一个字符集。

    4. 查看MySQL中查看支持的字符集和比较规则的语句如下:

      SHOW (CHARACTER SET|CHARSET) [LIKE 匹配的模式];
      SHOW COLLATION [LIKE 匹配的模式];
      로그인 후 복사
    5. MySQL有四个级别的字符集和比较规则

    • 服务器级别

      character_set_server表示服务器级别的字符集,collation_server表示服务器级别的比较规则。

    • 数据库级别

      创建和修改数据库时可以指定字符集和比较规则:

      CREATE DATABASE 数据库名
          [[DEFAULT] CHARACTER SET 字符集名称]
          [[DEFAULT] COLLATE 比较规则名称];
      
      ALTER DATABASE 数据库名
          [[DEFAULT] CHARACTER SET 字符集名称]
          [[DEFAULT] COLLATE 比较规则名称];
      로그인 후 복사
      로그인 후 복사

      character_set_database表示当前数据库的字符集,collation_database表示当前默认数据库的比较规则,这两个系统变量是只读的,不能修改。如果没有指定当前默认数据库,则变量与相应的服务器级系统变量具有相同的值。

    • 表级别

      创建和修改表的时候指定表的字符集和比较规则:

      CREATE TABLE 表名 (列的信息)
          [[DEFAULT] CHARACTER SET 字符集名称]
          [COLLATE 比较规则名称]];
      
      ALTER TABLE 表名
          [[DEFAULT] CHARACTER SET 字符集名称]
          [COLLATE 比较规则名称];
      로그인 후 복사
    • 列级别

      创建和修改列定义的时候可以指定该列的字符集和比较规则:

      CREATE TABLE 表名(
          列名 字符串类型 [CHARACTER SET 字符集名称] [COLLATE 比较规则名称],
          其他列...
      );
      
      ALTER TABLE 表名 MODIFY 列名 字符串类型 [CHARACTER SET 字符集名称] [COLLATE 比较规则名称];
      로그인 후 복사
      로그인 후 복사
    1. 从发送请求到接收结果过程中发生的字符集转换:

      • 客户端使用操作系统的字符集编码请求字符串,向服务器发送的是经过编码的一个字节串。

      • 서버는 character_set_client로 표시되는 문자 집합을 사용하여 클라이언트가 보낸 바이트 문자열을 디코딩한 다음 character_set_connection 코딩으로 표시되는 문자 집합에 따라 디코딩된 문자열을 디코딩합니다. . character_set_client代表的字符集进行解码,将解码后的字符串再按照character_set_connection代表的字符集进行编码。

      • 如果character_set_connection代表的字符集和具体操作的列使用的字符集一致,则直接进行相应操作,否则的话需要将请求中的字符串从character_set_connection代表的字符集转换为具体操作的列使用的字符集之后再进行操作。

      • 将从某个列获取到的字节串从该列使用的字符集转换为character_set_results代表的字符集后发送到客户端。

      • 客户端使用操作系统的字符集解析收到的结果集字节串。

      在这个过程中各个系统变量的含义如下:

      character_set_connection으로 표시되는 문자 집합이 특정 작업의 열에서 사용되는 문자 집합과 일치하면 해당 작업이 직접 수행됩니다. 그렇지 않으면 요청의 문자열이 필요합니다. character_set_connection에서 변경됩니다. code>가 나타내는 문자 집합은 작업이 수행되기 전에 특정 작업의 열에서 사용하는 문자 집합으로 변환됩니다.
      系统变量 描述
      character_set_client 服务器解码请求时使用的字符集
      character_set_connection 服务器处理请求时会把请求字符串从character_set_client转为character_set_connection
      character_set_results

      해당 열에서 얻은 바이트열을 해당 열이 사용하는 문자 집합에서 character_set_results로 표시되는 문자 집합으로 변환하여 클라이언트에 보냅니다.

    2. 클라이언트는 운영 체제의 문자 집합을 사용하여 수신된 결과 집합 바이트 문자열을 구문 분석합니다.

    이 과정에서 각 시스템 변수의 의미는 다음과 같습니다.

    character_set_client🎜요청을 디코딩할 때 서버에서 사용하는 문자 집합🎜🎜🎜character_set_connection🎜 🎜서버가 요청을 처리할 때 요청 문자열은 character_set_client에서 character_set_connection🎜🎜🎜character_set_results🎜🎜로 변환됩니다. 서버가 클라이언트 Set 🎜🎜🎜🎜🎜에 데이터를 반환할 때 일반적으로 이 세 가지 변수의 값은 클라이언트가 사용하는 문자 집합과 동일하게 유지하세요. 🎜🎜🎜🎜비교 규칙의 역할은 일반적으로 문자열 크기를 비교하고 특정 문자열 열을 정렬하는 표현식에 반영됩니다. 🎜🎜🎜🎜추천 학습: 🎜mysql 비디오 튜토리얼🎜🎜
    시스템 변수 설명 th>

    위 내용은 MySQL 문자 집합 및 비교 규칙을 이해하도록 안내합니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

    관련 라벨:
    원천:csdn.net
    본 웹사이트의 성명
    본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
    인기 튜토리얼
    더>
    최신 다운로드
    더>
    웹 효과
    웹사이트 소스 코드
    웹사이트 자료
    프론트엔드 템플릿
    회사 소개 부인 성명 Sitemap
    PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!