字符集和排序規則
字符集
我們可以為 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 命令檢視各種字符集支援的排序規則: