1. 程式人生 > 其它 >字符集和排序規則

字符集和排序規則

字符集

我們可以為 MySQL 伺服器、資料庫、表、字元型別的欄位以及字串常量指定一個字符集(Character Set)和排序規則(Collation)。其中,字符集決定了能夠儲存哪些字元,比如 ASCII 字符集只能儲存簡單的英文、數字和一些控制字元;GB2312 字符集可以儲存中文;Unicode 字符集能夠支援世界上的各種語言。排序規則定義了字符集中字元的排序和比較順序,包括是否區分大小寫,是否區分重音等。

MySQL 為不同的環境提供了多種字符集支援,可以使用SHOW CHARACTER SET命令檢視系統支援的所有字符集。例如:

SHOW CHARACTER SET;

Charset |Description                    |Default collation  |Maxlen|
--------|-------------------------------|-------------------|------|
armscii8|ARMSCII-8 Armenian             |armscii8_general_ci|     1|
ascii   |US ASCII                       |ascii_general_ci   |     1|
big5    |Big5 Traditional Chinese       |big5_chinese_ci    |     2|
...
utf32   |UTF-32 Unicode                 |utf32_general_ci   |     4|
utf8    |UTF-8 Unicode                  |utf8_general_ci    |     3|
utf8mb4 |UTF-8 Unicode                  |utf8mb4_0900_ai_ci |     4|

MySQL 8.0 開始,預設字符集改為 utf8mb4,而不是之前的 latin1;Maxlen 表示該字符集中單個字元最多可能佔用的位元組數,utf8mb4 中的一個字元最多佔用 4 個位元組,用於儲存表情符號(emoji);Default collation 表示該字符集預設的排序規則。

伺服器字符集

MySQL 伺服器端支援多個不同級別的字符集設定,包括伺服器級別、資料庫級別、表級別、欄位級別以及字串常量級別。使用 SHOW 命令檢視當前的設定:

SHOW variables LIKE '%character%';

Variable_name           |Value                         |
------------------------|------------------------------|
character_set_client    |utf8mb4                       |
character_set_connection|utf8mb4                       |
character_set_database  |utf8mb4                       |
character_set_filesystem|binary                        |
character_set_results   |                              |
character_set_server    |utf8mb4                       |
character_set_system    |utf8                          |
character_sets_dir      |/usr/share/mysql-8.0/charsets/|

其中,character_set_server 表示 MySQL 伺服器的全域性預設字符集,可以在伺服器配置檔案中 [mysqld] 部分的 character-set-server 選項或者啟動服務時通過命令列引數 --character-set-server 進行設定,也可以在執行時動態修改。

character_set_database 表示當前預設資料庫的字符集。當我們使用 CREATE DATABASE 或者 ALTER DATABASE 時,可以指定一個字符集和排序規則:

CREATE DATABASE db_name
    [[DEFAULT] CHARACTER SET charset_name]
    [[DEFAULT] COLLATE collation_name]

ALTER DATABASE db_name
    [[DEFAULT] CHARACTER SET charset_name]
    [[DEFAULT] COLLATE collation_name]

如果沒有指定字符集 CHARACTER SET 或者排序規則 COLLATE,MySQL 預設使用 character_set_server 伺服器字符集(utf8mb4)和排序規則(utf8mb4_0900_ai_ci)建立或者修改資料庫。

對於某個具體資料庫,可以使用 SHOW CREATE DATABASE 語句或者通過 information_schema.schemata 檢視檢視預設的字符集和排序規則。例如:

SHOW CREATE DATABASE hrdb;
Database|Create Database                                                                                                               |
--------|------------------------------------------------------------------------------------------------------------------------------|
hrdb    |CREATE DATABASE `hrdb` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */|

SELECT default_character_set_name, default_collation_name
FROM information_schema.schemata
WHERE SCHEMA_NAME = 'hrdb';
DEFAULT_CHARACTER_SET_NAME|DEFAULT_COLLATION_NAME|
--------------------------|----------------------|
utf8mb4                   |utf8mb4_0900_ai_ci    |

同樣,對於 CREATE TABLE 和 ALTER TABLE 語句,也可以指定一個字符集和排序規則:

CREATE TABLE table_name (column_list)
    [[DEFAULT] CHARACTER SET charset_name]
    [COLLATE collation_name]]

ALTER TABLE table_name
    [[DEFAULT] CHARACTER SET charset_name]
    [COLLATE collation_name]

如果沒有指定字符集 CHARACTER SET 或者排序規則 COLLATE,MySQL 預設使用 character_set_database 資料庫字符集和排序規則建立或者修改表。

對於某個具體的表,可以使用 SHOW CREATE TABLE 語句或者通過 information_schema.table 檢視檢視預設的字符集和排序規則。例如:

SHOW CREATE TABLE employee;
Table   |Create Table                                                                                                                                                                                                                                                   |
--------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
employee|CREATE TABLE `employee` (
  `emp_id` int NOT NULL,
  `emp_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `sex` varchar(10) CHARACTER SET utf8 NOT NULL,
  `dept_id` int NOT NULL,
  `manager` int DEFAULT NULL,
  `hire_date` date NOT NULL,
  `job_id` int NOT NULL,
  `salary` decimal(8,2) NOT NULL,
  `bonus` decimal(8,2) DEFAULT NULL,
  `email` varchar(100) CHARACTER SET utf8 NOT NULL,
  PRIMARY KEY (`emp_id`),
  UNIQUE KEY `uk_emp_email` (`email`),
  KEY `idx_emp_name` (`emp_name`),
  KEY `idx_emp_job` (`job_id`),
  KEY `idx_emp_manager` (`manager`),
  KEY `idx_emp_dept` (`dept_id`),
  CONSTRAINT `fk_emp_dept` FOREIGN KEY (`dept_id`) REFERENCES `department` (`dept_id`),
  CONSTRAINT `fk_emp_job` FOREIGN KEY (`job_id`) REFERENCES `job` (`job_id`),
  CONSTRAINT `fk_emp_manager` FOREIGN KEY (`manager`) REFERENCES `employee` (`emp_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci|

SELECT table_collation
FROM information_schema.tables
WHERE table_name = 'employee';
TABLE_COLLATION   |
------------------|
utf8mb4_0900_ai_ci|

每個 CHAR、VARCHAR、TEXT、ENUM、SET 型別的欄位也可以擁有自己的字符集和排序規則:

col_name {CHAR | VARCHAR | TEXT} (col_length)
    [CHARACTER SET charset_name]
    [COLLATE collation_name]

col_name {ENUM | SET} (val_list)
    [CHARACTER SET charset_name]
    [COLLATE collation_name]

如果沒有指定字符集 CHARACTER SET 或者排序規則 COLLATE,MySQL 預設使用表的字符集和排序規則建立或者修改欄位。使用 SHOW CREATE TABLE 語句可以查看錶中欄位的字符集和排序規則。

MySQL 字符集和排序規則的優先級別為欄位級別大於表級別,表級別大於資料庫級別,資料庫級別大於伺服器級別。

另外,MySQL 中的字串常量也有字符集和排序規則。例如,以下字串常量使用相同的字符集:

SELECT '資料庫';
SELECT _utf8mb4'資料庫';
SELECT _utf8mb4'資料庫' COLLATE utf8mb4_0900_ai_ci;

如果沒有指定字符集或者排序規則 COLLATE,MySQL 使用預設的連線字符集 character_set_connection。

字符集和排序規則會對一些 MySQL 字元函式產生影響,例如:

SELECT length('abc'), char_length('abc'), length('資料庫'), char_length('資料庫');
length('abc')|char_length('abc')|length('資料庫')|char_length('資料庫')|
-------------|------------------|---------------|--------------------|
            3|                 3|              9|                   3|

LENGTH 函式返回以位元組為單位的字串長度,多位元組字符集中字元佔用的位元組數可能不同;CHAR_LENGTH 函式返回以字元為單位的字串長度。

CONVERT(expr USING transcoding_name) 函式可以實現不同字符集之間的資料轉換。例如:

SELECT CONVERT('MySQL' USING ascii);

客戶端字符集

MySQL 客戶端應用和伺服器連線之後,通過連線輸入 SQL 語句,傳送命令,接收伺服器端的結果或者錯誤資訊。在這個過程中,還會涉及到以下字符集設定:

  • 客戶端語句使用的字符集,MySQL 使用 character_set_client 的設定作為客戶端字符集;
  • 伺服器接收到語句之後需要將其轉換為哪種字符集,MySQL 使用 character_set_connection 的值作為轉換的目標字符集。同時它也是字串常量預設的字符集;
  • 伺服器在返回查詢結果(包括欄位名、欄位值、錯誤資訊等)之前需要將其轉換為哪種字符集,MySQL 使用 character_set_results 作為這種轉換的目標字符集。

客戶端連線的字符集可以通過以下幾種方法進行設定:

  • 連線資料庫之後,使用 SET NAMES 'charset_name' [COLLATE 'collation_name'] 命令進行設定。例如:SET NAMES 'utf8'; 該語句相當於同時設定了 character_set_client、character_set_results 以及 character_set_connection 的值。
  • 使用 SET CHARACTER SET 'charset_name' 命令進行設定。例如:SET CHARACTER SET 'utf8'; 該語句相當於同時設定了 character_set_client、character_set_results 的值,並且將 character_set_connection 的值設定為 character_set_database。
  • 如果客戶端應用支援 --default-character-set 選項,例如 mysql、mysqladmin 等,可以在配置檔案中 [mysql] 部分的 default-character-set 配置項進行設定。
  • 某些 MySQL 驅動程式允許在連線字串中指定一個字符集編碼,例如 JDBC 中的 characterEncoding。

為了避免不同字符集轉換可能帶來的問題,最好將客戶端連線字符集和伺服器的字符集設定為一致。

系統變數 character_set_system 是伺服器儲存元資料(Metadata)使用的字符集,總是設定為 utf8。character_set_filesystem 用於設定檔案系統的字符集,主要影響開啟檔案時對檔名的解析。character_sets_dir 表示字符集的儲存目錄。

國家字符集

SQL 標準定義了兩種使用特定字符集的字串型別:NCHAR(NATIONAL CHAR)和 NVARCHAR(NATIONAL VARCHAR)。MySQL 選擇 utf8(不是 utf8mb4)作為這種型別的預定義字符集,以下三種形式的定義等價:

CHAR(10) CHARACTER SET utf8
NATIONAL CHARACTER(10)
NCHAR(10)

以下語句等價:

VARCHAR(10) CHARACTER SET utf8
NATIONAL VARCHAR(10)
NVARCHAR(10)
NCHAR VARCHAR(10)
NATIONAL CHARACTER VARYING(10)
NATIONAL CHAR VARYING(10)

對於國家字符集中的字串常量,可以使用 N'literal' 的形式進行表示。例如:

SELECT N'資料庫';
SELECT n'資料庫';
SELECT _utf8'資料庫';

排序規則

每個 MySQL 字符集可以支援一個或者多個排序規則,用於定義每個字元的比較規則,包括是否區分大小寫,是否區分重音等。MySQL 使用 SHOW COLLATION 命令檢視各種字符集支援的排序規則: