mysql 中非 utf8 列的建议字符集
Suggested character set for non utf8 columns in mysql
目前,我对 mysql 中的所有字符列使用 VARCHAR
/TEXT
和 utf8_general_ci
。现在我想改进数据库 layout/performance.
到目前为止我想到的是更好地使用
CHAR
而不是 VARCHAR
作为 GUID 或会话 ID 的固定长度列
- 对于长度为 1 或 2 的小列也使用
CHAR
?
由于处理问题,我不想将我的 GUID 保存为 BINARY(16)
,我宁愿将它们保存为 CHAR(32)
以特别改进密钥。 (从 utf8 切换到一些 1 字节字符集时,我什至可以节省 2/3)
- 那么,对于此类列,最好的字符集是什么?编码?拉丁语1?二进制?哪个排序规则?
- 什么 characterset/collation 用于我不需要 utf8 支持但需要正确排序的其他列。二进制文件会失败吗?
在同一个 mysql (innodb) table 中混合使用不同的字符集是一种好习惯吗?或者当所有列在相同的 table 中具有相同的字符集时,我会获得更好的性能吗?甚至数据库?
GUID/UUID/MD5/SHA1 都是十六进制和破折号。对于他们
CHAR(..) CHARACTER SET ascii COLLATE ascii_general_ci
在比较十六进制字符串时,这将允许 A
=a
。
对于 Base64 事物,使用
CHAR(..) CHARACTER SET ascii COLLATE ascii_bin
BINARY(..)
因为 A
在语义上与 a
不同 。
进一步说明...
- 如果你给它一个无效的 8 位值,utf8 会吐给你。
- ascii 向你吐出任何 8 位值。
- latin1 接受任何东西——因此你以后的问题
- 在具有不同字符集 and/or 排序规则的 table 中有不同的列是完全可以的。
- table 上的 charset/collation 只是一个 默认值 ,可以覆盖列定义。
BINARY
可能比任何 _bin
排序规则快一点,但还不足以引起注意。
- 对真正固定长度的列使用
CHAR
;请勿将其用于其他情况,误导用户。
%_bin
比%_general_ci
快,比其他排序规则快。同样,您将很难衡量差异。
- 切勿使用
TINYTEXT
或 TINYBLOB
。
- 为了正确编码,请使用适当的字符集。
- 对于 "proper sorting",请使用适当的排序规则。请参阅下面的示例。
- 对于代表多种语言的 "proper sorting",而您使用的是
utf8mb4
,请使用 utf8mb4_unicode_520_ci
(如果使用 8.0 版,则使用 utf8mb4_900_ci
)。 520 和 900 指的是 Unicode 标准;将来可能会出现新的排序规则。
如果您完全使用捷克语,请考虑这些字符集和排序规则。我按首选顺序列出它们:
mysql> show collation like '%czech%';
+------------------+---------+-----+---------+----------+---------+
| Collation | Charset | Id | Default | Compiled | Sortlen |
+------------------+---------+-----+---------+----------+---------+
| utf8mb4_czech_ci | utf8mb4 | 234 | | Yes | 8 | -- opens up the world
| utf8_czech_ci | utf8 | 202 | | Yes | 8 | -- opens up most of the world
| latin2_czech_cs | latin2 | 2 | | Yes | 4 | -- kinda like latin1
其余为"useless":
| cp1250_czech_cs | cp1250 | 34 | | Yes | 2 |
| ucs2_czech_ci | ucs2 | 138 | | Yes | 8 |
| utf16_czech_ci | utf16 | 111 | | Yes | 8 |
| utf32_czech_ci | utf32 | 170 | | Yes | 8 |
+------------------+---------+-----+---------+----------+---------+
7 rows in set (0.00 sec)
更多
- 使用较小数据类型(在适当的情况下)的原因是缩小数据集,从而减少 I/O,从而使事物更易于缓存,从而使程序 运行 更快。这对于庞大的数据集尤为重要;它对于中小型数据集不太重要。
ENUM
是 1 个字节,但表现得像一个字符串。所以你得到了"best of both worlds"。 (有缺点,ENUM
vs TINYINT
vs VARCHAR
的拥护者中有 'religious war'。)
- 通常 "short" 的列的长度始终相同。
country_code
总是 2 个字母,总是 ascii,总是可以受益于不区分大小写的排序规则。所以 CHAR(2) CHARACTER SET ascii COLLATE ascii_general_ci
是最优的。如果你有一些东西有时是 1 个字符,有时是 2 个字符,那么抛硬币;不管你做什么都不会有太大的不同。
VARCHAR
(最多 255)附加了一个额外的 1 字节长度。因此,如果您的字符串长度 完全不同 ,VARCHAR
至少与 CHAR
一样好。所以简化你的大脑处理:"variable length --> `VARCHAR".
BIT
,视版本而定,可以作为 1 字节 TINYINT UNSIGNED
实现。如果您的 table 中只有几位,则不值得担心。
- 我的一个 Rules of Thumb 说,如果您不太可能获得 10% 的改进,请继续进行其他优化。我们在这里讨论的大部分内容都低于 10%(在本例中为 space)。不过,在写
CREATE TABLE
时养成思考它的习惯。我经常看到带有 BIGINT
和 DOUBLE
(每个 8 个字节)的 tables 可以很容易地使用较小的列。有时节省超过 50% (space)。
- "space"如何转化为"speed"。微小的 tables -> 微小的百分比。巨大的 tables -> 在某些情况下是 10 倍。 (这是 10 倍,而不是 10%。)(UUID 是在巨大 tables 上获得非常糟糕性能的一种方式。)
枚举
- 行为和感觉像一个字符串,但只占用一个字节。 (一个字节间接转化为轻微的速度提升。)
- 当少于 10 个不同值时实用。
- 如果频繁添加新值是不切实际的 -- 需要
ALTER TABLE
,但 可以 为 "inplace"。
- 建议以
'unknown'
(或类似的东西)开始列表,并将列设为 NOT NULL
(相对于 NULL
)。
- 枚举的字符集必须是用于连接的任何字符集。选择并不重要,除非你有 collate 相等的选项(例如,
A
与 a
)。
目前,我对 mysql 中的所有字符列使用 VARCHAR
/TEXT
和 utf8_general_ci
。现在我想改进数据库 layout/performance.
到目前为止我想到的是更好地使用
CHAR
而不是VARCHAR
作为 GUID 或会话 ID 的固定长度列- 对于长度为 1 或 2 的小列也使用
CHAR
?
由于处理问题,我不想将我的 GUID 保存为 BINARY(16)
,我宁愿将它们保存为 CHAR(32)
以特别改进密钥。 (从 utf8 切换到一些 1 字节字符集时,我什至可以节省 2/3)
- 那么,对于此类列,最好的字符集是什么?编码?拉丁语1?二进制?哪个排序规则?
- 什么 characterset/collation 用于我不需要 utf8 支持但需要正确排序的其他列。二进制文件会失败吗?
在同一个 mysql (innodb) table 中混合使用不同的字符集是一种好习惯吗?或者当所有列在相同的 table 中具有相同的字符集时,我会获得更好的性能吗?甚至数据库?
GUID/UUID/MD5/SHA1 都是十六进制和破折号。对于他们
CHAR(..) CHARACTER SET ascii COLLATE ascii_general_ci
在比较十六进制字符串时,这将允许 A
=a
。
对于 Base64 事物,使用
CHAR(..) CHARACTER SET ascii COLLATE ascii_bin
BINARY(..)
因为 A
在语义上与 a
不同 。
进一步说明...
- 如果你给它一个无效的 8 位值,utf8 会吐给你。
- ascii 向你吐出任何 8 位值。
- latin1 接受任何东西——因此你以后的问题
- 在具有不同字符集 and/or 排序规则的 table 中有不同的列是完全可以的。
- table 上的 charset/collation 只是一个 默认值 ,可以覆盖列定义。
BINARY
可能比任何_bin
排序规则快一点,但还不足以引起注意。- 对真正固定长度的列使用
CHAR
;请勿将其用于其他情况,误导用户。 %_bin
比%_general_ci
快,比其他排序规则快。同样,您将很难衡量差异。- 切勿使用
TINYTEXT
或TINYBLOB
。 - 为了正确编码,请使用适当的字符集。
- 对于 "proper sorting",请使用适当的排序规则。请参阅下面的示例。
- 对于代表多种语言的 "proper sorting",而您使用的是
utf8mb4
,请使用utf8mb4_unicode_520_ci
(如果使用 8.0 版,则使用utf8mb4_900_ci
)。 520 和 900 指的是 Unicode 标准;将来可能会出现新的排序规则。
如果您完全使用捷克语,请考虑这些字符集和排序规则。我按首选顺序列出它们:
mysql> show collation like '%czech%';
+------------------+---------+-----+---------+----------+---------+
| Collation | Charset | Id | Default | Compiled | Sortlen |
+------------------+---------+-----+---------+----------+---------+
| utf8mb4_czech_ci | utf8mb4 | 234 | | Yes | 8 | -- opens up the world
| utf8_czech_ci | utf8 | 202 | | Yes | 8 | -- opens up most of the world
| latin2_czech_cs | latin2 | 2 | | Yes | 4 | -- kinda like latin1
其余为"useless":
| cp1250_czech_cs | cp1250 | 34 | | Yes | 2 |
| ucs2_czech_ci | ucs2 | 138 | | Yes | 8 |
| utf16_czech_ci | utf16 | 111 | | Yes | 8 |
| utf32_czech_ci | utf32 | 170 | | Yes | 8 |
+------------------+---------+-----+---------+----------+---------+
7 rows in set (0.00 sec)
更多
- 使用较小数据类型(在适当的情况下)的原因是缩小数据集,从而减少 I/O,从而使事物更易于缓存,从而使程序 运行 更快。这对于庞大的数据集尤为重要;它对于中小型数据集不太重要。
ENUM
是 1 个字节,但表现得像一个字符串。所以你得到了"best of both worlds"。 (有缺点,ENUM
vsTINYINT
vsVARCHAR
的拥护者中有 'religious war'。)- 通常 "short" 的列的长度始终相同。
country_code
总是 2 个字母,总是 ascii,总是可以受益于不区分大小写的排序规则。所以CHAR(2) CHARACTER SET ascii COLLATE ascii_general_ci
是最优的。如果你有一些东西有时是 1 个字符,有时是 2 个字符,那么抛硬币;不管你做什么都不会有太大的不同。 VARCHAR
(最多 255)附加了一个额外的 1 字节长度。因此,如果您的字符串长度 完全不同 ,VARCHAR
至少与CHAR
一样好。所以简化你的大脑处理:"variable length --> `VARCHAR".BIT
,视版本而定,可以作为 1 字节TINYINT UNSIGNED
实现。如果您的 table 中只有几位,则不值得担心。- 我的一个 Rules of Thumb 说,如果您不太可能获得 10% 的改进,请继续进行其他优化。我们在这里讨论的大部分内容都低于 10%(在本例中为 space)。不过,在写
CREATE TABLE
时养成思考它的习惯。我经常看到带有BIGINT
和DOUBLE
(每个 8 个字节)的 tables 可以很容易地使用较小的列。有时节省超过 50% (space)。 - "space"如何转化为"speed"。微小的 tables -> 微小的百分比。巨大的 tables -> 在某些情况下是 10 倍。 (这是 10 倍,而不是 10%。)(UUID 是在巨大 tables 上获得非常糟糕性能的一种方式。)
枚举
- 行为和感觉像一个字符串,但只占用一个字节。 (一个字节间接转化为轻微的速度提升。)
- 当少于 10 个不同值时实用。
- 如果频繁添加新值是不切实际的 -- 需要
ALTER TABLE
,但 可以 为 "inplace"。 - 建议以
'unknown'
(或类似的东西)开始列表,并将列设为NOT NULL
(相对于NULL
)。 - 枚举的字符集必须是用于连接的任何字符集。选择并不重要,除非你有 collate 相等的选项(例如,
A
与a
)。