我有一个utf8
包含 > 80M 记录的表,其中一列 ( char(6) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL
) 可以只包含拉丁符号 ( [a-zA-Z0-9]
)。将此列转换为latin1是否有意义?
MySQL文档说:
要使用 UTF-8 节省空间,请使用 VARCHAR 而不是 CHAR。否则,MySQL 必须为 CHAR CHARACTER SET utf8 列中的每个字符保留三个字节,因为这是最大可能的字符长度。例如,MySQL 必须为 CHAR(10) CHARACTER SET utf8 列保留 30 个字节。
我做了一个测试 - 创建了 2 个具有相同 50M 记录的表:
CREATE TABLE `t_utf8` (
`c_1` char(6) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
UNIQUE KEY `index_t_utf8_on_c_1` (`c_1`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;
CREATE TABLE `t_lat` (
`c_1` char(6) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL,
UNIQUE KEY `index_t_lat_on_c_1` (`c_1`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;
Run Code Online (Sandbox Code Playgroud)
但是 MySQL 说它们的大小几乎相同:
Name: t_lat
Engine: InnoDB
Version: 10
Row_format: Compact
Rows: 57557700
Avg_row_length: 30
Data_length: 1741668352
Max_data_length: 0
Index_length: 0
Data_free: 2097152
Auto_increment: NULL
Collation: utf8_general_ci
Create_options: row_format=COMPACT
Name: t_utf8
Engine: InnoDB
Version: 10
Row_format: Compact
Rows: 57554528
Avg_row_length: 31
Data_length: 1810874368
Max_data_length: 0
Index_length: 0
Data_free: 3145728
Auto_increment: NULL
Collation: utf8_general_ci
Create_options: row_format=COMPACT
Run Code Online (Sandbox Code Playgroud)
为什么会这样?
PS:我用 MyISAM 做了同样的测试并得到了预期的好处:latin1 - 383Mb,utf8 - 1Gb 的表。但是为什么它不适用于 InnoDB?
简短的回答:别打扰。
长答案:
CHAR
除了真正固定长度的字符串之外,不要使用。它们几乎总是 ascii,例如 country_code、postal_code、UUID、hex、md5 等。
在创建列/表时养成明确说出 ascii 或 utf8mb4 的习惯,除非您有需要其他内容的异常情况。