2017-09-20 85 views
1

目前,我正在使用VARCHAR/TEXTutf8_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)表中混合使用不同的字符集是不是很好的做法?或者,当所有列在同一个表中具有相同的字符集时,我是否会获得更好的性能?甚至数据库?

+0

如果字符超出ASCII范围,UTF-8仅使用多个字节。字符串化的UUID(如果这就是您使用的GUID)始终落在该范围内。 – robertklep

+0

@robertklep我听说,这是有道理的,但我认为这不适用于指数(空间消耗)!?例如,在将utf8列转换为latin1时,'EXPLAIN SELECT'显示2/3更小的'key_len'值。 – toshniba

+0

啊,我没有考虑(我对MySQL/InnoDB索引如何实现不了解太多)。 – robertklep

回答

1

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更快,这比其他排序规则更快。再一次,你会很难测量差异。
  • 千万不要使用TINYTEXTTINYBLOB
  • 为了正确编码,请使用适当的字符集。
  • 对于“正确排序”,请使用适当的排序规则。见下面的例子。
  • 对于表示多种语言且正在使用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个字节,但行为像一个字符串。所以你得到了“两全其美”。 (存在缺陷,在ENUMTINYINTVARCHAR之间的倡导者之间存在“宗教战争”。)
  • 通常,“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时应养成考虑它的习惯。我经常看到带有BIGINTDOUBLE(每个8字节)的表格,可以很容易地使用较小的列。有时节省50%以上(空间)。
  • “空间”如何转化为“速度”?微小的表格 - >很小的百分比。巨大的表 - >在某些情况下10倍。 (这是10倍,而不是10%。)(UUID的是获得巨大的表非常糟糕表现的一种方式。)

ENUM

  • 行为,感觉就像一个字符串,但需要只有一个字节。(一个字节间接转化为轻微的速度提升。)
  • 实际应用的时候少于10个不同的值。
  • 如果经常添加一个新的值不切实际 - 需要ALTER TABLE,尽管它可以是“inplace”。
  • 建议从'unknown'(或类似的东西)开始列表,并使列NOT NULL(与NULL相比)。
  • 枚举的字符集需要是其他方式用于连接的。除非您有整理等于(例如,Aa)的选项,否则选择并不重要。
+0

非常感谢!使用较小的整数(<4B)和位是否合理?我听说mysqls'ENUM'是一个很好的练习方法吗? CHAR(1)和(2)列呢?当一些(百分比?)未被填充时,请使用VARCHAR? – toshniba

+0

在某些情况下,我喜欢'ENUM';有些人不喜欢他们。我反对'CHAR'--不包括真正固定长度的专栏;然后只使用适当的'CHARACTER SET'(这是_usually_'ascii')。 –

+0

感谢@rick,但这并不是很有用,因为你没有说明为什么你'喜欢'枚举(优点/缺点),我们已经知道关于字符的提到的东西。也许你可以解释为什么/何时使用'ENUM'是有意义的(特别是与性能有关),并且当许多/某些行(百分比?)在该列中没有值时,使用'CHAR'仍然有意义。 – toshniba