MySQL 8.0 支持 Unicode 9.0 的编码是utf8mb4
。它是变长的,每个字符占用 1~4 字节。关于字节和字符类型的可变长度有许多细微差别:
- 当创建 VARCHAR(n) 列时,n 代表字符数。储存该类型所需的字节数最多可能达到 n 的 4 倍。
- 通常 InnoDB 储存引擎对于 VARCHAR, CHAR, TEXT 类型都会储存为可变长的 utf8mb4 编码,在索引和在行数据中都是这样。
- 内存临时表是定长的。这会导致在使用 utf8mb4 编码一些情况下,内存临时表要么更大,要么是大到要用硬盘来存放溢出内存的部分。
- 用于排序的缓冲区是变长的(从 5.7 版本起)。
- EXPLAIN 会展示变长索引的最大长度,但实际所需的储存空间通常低得多。
例子37展示了 EXPLAIN 报告了使用 latin1 编码、 CHAR(52) 类型的索引使用情况。把表的储存编码修改为 utf8mb4 后,储存占用空间没有变大,但 EXPLAIN 的键长度 key_length
增加了:
例子37:EXPLAIN 展示索引的最大键长度(latin1 编码)
EXPLAIN FORMAT=JSON
SELECT * FROM Country WHERE name='Canada';
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "1.20"
},
"table": {
"table_name": "Country",
"access_type": "ref",
"possible_keys": [
"Name"
],
"key": "Name",
"used_key_parts": [
"Name"
],
"key_length": "52", # CHAR(52)
"ref": [
"const"
],
"rows_examined_per_scan": 1,
"rows_produced_per_join": 1,
"filtered": "100.00",
"cost_info": {
"read_cost": "1.00",
"eval_cost": "0.20",
"prefix_cost": "1.20",
"data_read_per_join": "264"
},
"used_columns": [
...
]
}
}
}
例子38:EXPLAIN 展示索引的最大键长度(utf8mb4 编码)
-- 修改表编码为 utf8mb4
ALTER TABLE Country CONVERT TO CHARACTER SET utf8mb4;
EXPLAIN FORMAT=JSON
SELECT * FROM Country WHERE name='Canada';
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "1.20"
},
"table": {
"table_name": "Country",
"access_type": "ref",
"possible_keys": [
"Name"
],
"key": "Name",
"used_key_parts": [
"Name"
],
"key_length": "208", # CHAR(52) * 4 = 208
"ref": [
"const"
],
"rows_examined_per_scan": 1,
"rows_produced_per_join": 1,
"filtered": "100.00",
"cost_info": {
"read_cost": "1.00",
"eval_cost": "0.20",
"prefix_cost": "1.20",
"data_read_per_join": "968"
},
"used_columns": [
...
]
}
}
}
译自:
Character Sets – The Unofficial MySQL 8.0 Optimizer Guide