为什么从utf8改为utf8mb4会减慢我的数据库速度?

hwamh0ep  于 2021-06-21  发布在  Mysql
关注(0)|答案(1)|浏览(967)

我的php web应用程序中的所有mysql表都是使用utf8编码的myisam。因为记录可以在脱机时从一个伴随应用程序生成,所以我的表键是随机生成的,字母数字varchars;这些字段通过utf8\u bin编码设置为二进制,因此它们可以区分大小写。
我最近决定更改所有文本字段的编码,以支持一些用户喜欢输入的emojis。我接着把所有的utf8字段都改成了utf8mb4,包括键。我立即开始看到性能问题,其中一个较大表上的复杂select查询花费了一分钟以上,然后其他查询排队等待表锁。我将表上主键字段的编码改回utf8,性能恢复正常。几天后,我再次将该字段更改为utf8mb4,查询再次开始排队,并将其更改为恢复正常性能。
因此,运行平稳:

`ID` varchar(8) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''

但这会带来问题:

`ID` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT ''

我读到的所有东西都说utf8和utf8mb4应该有相同的性能,但我看到我的情况有明显的不同。这有道理吗?
将关键字段保留在utf8并不是什么问题,因为我预计在那里使用的不仅仅是简单的字母数字字符。但我希望将所有字段设置为相同的编码,只是为了保持一致性和维护的简单性(不必记住将用户填充的字段设置为一种编码,将关键字段设置为另一种编码)。
关于@mandyshaw的评论
当我使用sequel pro mac应用程序处理数据库时,控制台会不断显示成对的 SET NAMES 'utf8' 以及 SET NAMES 'utf8mb4' 条目,所以这并不意味着所有设置都是正确的。不过,我目前的情况是:

MySQL [(none)]> SHOW GLOBAL VARIABLES WHERE Variable_name LIKE 'character\_set\_%' OR Variable_name LIKE 'collation%';
+--------------------------+--------------------+
| Variable_name            | Value              |
+--------------------------+--------------------+
| character_set_client     | utf8mb4            |
| character_set_connection | utf8mb4            |
| character_set_database   | utf8mb4            |
| character_set_filesystem | binary             |
| character_set_results    | utf8mb4            |
| character_set_server     | utf8mb4            |
| character_set_system     | utf8               |
| collation_connection     | utf8mb4_unicode_ci |
| collation_database       | utf8mb4_unicode_ci |
| collation_server         | utf8mb4_unicode_ci |
+--------------------------+--------------------+

我读到了 character_set_system 无法从utf8和 character_set_filesystem 应该是二进制的。
sequel pro的连接编码设置为autodetect,但是当我显式地将其更改为utf8mb4,然后打开一个新的连接时,我仍然可以在控制台中看到所有这些编码更改。
还有什么我需要改变的使用这种编码一致?

whitzsjs

whitzsjs1#

utf实际上是utfmb3,每个字符最多使用3个字节,而utfmb4每个字符最多使用4个字节。对于varchar列,这通常不会有太大的区别,因为mysql只存储所需的字节数(除非您使用row\u format=fixed创建了myisam表)。
但是,在查询执行期间,mysql可能会在内存存储引擎中创建临时表,该引擎不支持可变长度行。这些临时表有一个最大大小,如果超过这个大小,临时表将转换为myisam/innodb中的表(取决于您的mysql版本)。状态变量 Created_tmp_disk_tables 每次发生这种情况时都将递增。如果是这样,试着看看它是否有助于增加 max_heap_table_sizetmp_table_size .
或者,升级到MySQL8.0,其中新的支持可变长度行的存储引擎用于内部临时表。

相关问题