为mysql中的非utf8列建议的字符集
问题描述:
目前,我正在使用VARCHAR
/TEXT
和utf8_general_ci
对于mysql中的所有字符列。现在我想改进数据库布局/性能。为mysql中的非utf8列建议的字符集
我想通些什么,到目前为止是更好地利用
-
CHAR
,而不是VARCHAR
为固定长度的列的GUID或会话ID - 也使用
CHAR
对于具有1长度也许2个小列?
因为我不想去宽我的GUID保存为BINARY(16)
因为处理问题,我宁愿将其保存为CHAR(32)
特别提高键。 (当从utf8切换到某些1字节字符集时,我甚至可以节省2/3)
- 那么对于这样的列,最佳字符集是什么? ASCII? LATIN1? BINARY?哪种整理?
- 什么字符集/整理用于其他列,我不需要utf8支持,但需要适当的排序。二进制文件会失败?
在同一个mysql(innodb)表中混合使用不同的字符集是不是很好的做法?或者,当所有列在同一个表中具有相同的字符集时,我是否会获得更好的性能?甚至数据库?
答
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
。
还注意到......
- UTF8你吐出如果你给它一个无效的8位值。
- ascii吐出任何8位值。
- latin1接受任何东西 - 因此你的问题在路上
- 在具有不同字符集和/或排序规则的表中使用不同的列是完全可以的。
- 表格上的字符集/排序规则只是默认,适合在列定义中重写。
-
BINARY
可能比任何_bin
排序规则稍快,但不足以注意到。 - 使用
CHAR
表示真正固定长度的列;不要误导用户在其他情况下使用它。 -
%_bin
比%_general_ci
更快,这比其他排序规则更快。再一次,你会很难测量差异。 - 千万不要使用
TINYTEXT
或TINYBLOB
。 - 为了正确编码,请使用适当的字符集。
- 对于“正确排序”,请使用适当的排序规则。见下面的例子。
- 对于表示多种语言且正在使用
utf8mb4
的“正确排序”,请使用utf8mb4_unicode_520_ci
(或utf8mb4_900_ci
,如果使用版本8.0)。 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
其余的是 “无用”:
| 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个字节,但行为像一个字符串。所以你得到了“两全其美”。 (存在缺陷,在ENUM
与TINYINT
与VARCHAR
之间的倡导者之间存在“宗教战争”。) - 通常,“short”列总是长度相同。 A
country_code
总是2个字母,总是ascii,总是可以受益于不区分大小写的整理。所以CHAR(2) CHARACTER SET ascii COLLATE ascii_general_ci
是最佳的。如果你有些东西有时是1个字符,有时是2个,然后翻转一个硬币;不管你做什么都不会有太大的变化。 -
VARCHAR
(最多255)附加一个额外的1字节长度。因此,如果您的字符串的长度变化为,则所有,VARCHAR
至少与CHAR
一样好。所以简化你的大脑处理:“可变长度 - >`VARCHAR”。 -
BIT
,根据版本,可以实现为1字节的TINYINT UNSIGNED
。如果你的桌子上只有几个点,那就不值得担心了。 - 我的Rules of Thumb之一表示,如果您不太可能获得10%的改进,请继续进行其他优化。我们在这里讨论的大部分内容都低于10%(本例中为空间)。不过,在编写
CREATE TABLE
时应养成考虑它的习惯。我经常看到带有BIGINT
和DOUBLE
(每个8字节)的表格,可以很容易地使用较小的列。有时节省50%以上(空间)。 - “空间”如何转化为“速度”?微小的表格 - >很小的百分比。巨大的表 - >在某些情况下10倍。 (这是10倍,而不是10%。)(UUID的是获得巨大的表非常糟糕表现的一种方式。)
ENUM
- 行为,感觉就像一个字符串,但需要只有一个字节。(一个字节间接转化为轻微的速度提升。)
- 实际应用的时候少于10个不同的值。
- 如果经常添加一个新的值不切实际 - 需要
ALTER TABLE
,尽管它可以是“inplace”。 - 建议从
'unknown'
(或类似的东西)开始列表,并使列NOT NULL
(与NULL
相比)。 - 枚举的字符集需要是其他方式用于连接的。除非您有整理等于(例如,
A
与a
)的选项,否则选择并不重要。
如果字符超出ASCII范围,UTF-8仅使用多个字节。字符串化的UUID(如果这就是您使用的GUID)始终落在该范围内。 – robertklep
@robertklep我听说,这是有道理的,但我认为这不适用于指数(空间消耗)!?例如,在将utf8列转换为latin1时,'EXPLAIN SELECT'显示2/3更小的'key_len'值。 – toshniba
啊,我没有考虑(我对MySQL/InnoDB索引如何实现不了解太多)。 – robertklep