MySQL 复制中的字符集
-
27-09-2019 - |
题
我该如何确保复制使用 latin1 而不是 utf-8?
我正在 Linux 系统上的 MySQL 5.1.22 服务器(主服务器)和 FreeBSD 系统上的 MySQL 5.1.42 服务器(从服务器)之间迁移。我的复制效果很好,但是当我的 varchar 中包含非 ASCII 字符时,它们会变得“奇怪”。Linux/MySQL-5.1.22 显示以下字符集变量:
character_set_client=latin1
character_set_connection=latin1
character_set_database=latin1
character_set_filesystem=binary
character_set_results=latin1
character_set_server=latin1
character_set_system=utf8
character_sets_dir=/usr/share/mysql/charsets/
collation_connection=latin1_swedish_ci
collation_database=latin1_swedish_ci
collation_server=latin1_swedish_ci
虽然 FreeBSD 显示
character_set_client=utf8
character_set_connection=utf8
character_set_database=utf8
character_set_filesystem=binary
character_set_results=utf8
character_set_server=utf8
character_set_system=utf8
character_sets_dir=/usr/local/share/mysql/charsets/
collation_connection=utf8_general_ci
collation_database=utf8_general_ci
collation_server=utf8_general_ci
从 MySQL CLI 设置任何这些变量都没有效果,在 my.cnf 或命令行中设置它们会导致服务器无法启动。
当然,两台服务器都以相同的方式创建有问题的表,在本例中使用 DEFAULT CHARSET=latin1。让我举一个例子:
CREATE TABLE `test` (
`test` varchar(5) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
当我在主服务器上,在 Latin1 终端中执行“INSERT INTO test VALUES ('æøå')”时,当我从基于 Latin1 的终端中选择它时,这会在从服务器上执行
+--------+
| test |
+--------+
| æøå |
+--------+
在复制从站上基于 UTF-8 的终端上,测试包含:
+--------+
| test |
+--------+
| æøå |
+--------+
所以我的结论是它被转换为utf8,即使表定义是latin1。这是一个正确的结论吗?
当然,在 master 上,在 latin1 终端中,它仍然显示:
+------+
| test |
+------+
| æøå |
+------+
由于两个系统字符集都是 utf-8,如果我将两个终端都设置为 utf-8,并在使用 utf-8 终端的主机上再次执行“INSERT INTO test VALUES ('æøå')”,在使用 utf-8 终端的从机上执行“INSERT INTO test VALUES ('æøå')”我得到:
+------------+
| test |
+------------+
| æøà |
+------------+
如果我的结论是正确的,那么我所有复制的数据都将转换为utf8(如果是utf8,则将其视为latin1并转换为utf8),而表中的所有旧数据,如CREATE TABLE所示,都是latin1。如果不是因为遗留应用程序依赖于 latin1,我很想将其全部转换为 utf-8,所以我需要在它们仍然存在时将其保留为 latin1。
我该怎么做才能确保复制读取 latin1、将其视为 latin1 并将其作为 latin1 写入从属设备?
干杯
尼克
解决方案
在一般情况下,则必须使用的MySQL的完全相同的配置文件和版本上的从(除了在升级/迁移方案,并且其必须是像SERVER_ID从站不同的几件事情)。
您会希望您的脚本数据库设置,使您的数据库服务器软件部署的一部分。至关重要的是,所有数据库服务器,包括那些在非生产环境,使用完全相同的配置。
失败同步的CONFIGS会导致意外的错误。
我不知道为什么你觉得有必要给你不同的服务器上运行不同的操作系统,但你会为您的行动人员的生活更加困难,如果你这样做。
其他提示
不支持全局character_set_% 和 collation% 参数不同的服务器之间的复制。
http://dev.mysql.com/doc/refman/5.6/en/replication-features-charset.html
-- on both servers check the output of...
SHOW VARIABLES LIKE 'char%';
SHOW VARIABLES LIKE 'collat%';
如果集和排序规则不同,不仅复制会失败,而且可能会导致转换集/排序规则期间出现不同的排序顺序和字符丢失。如果使用基于语句的复制,排序顺序可能会影响插入/更新等操作。
您最好将新服务器配置为使用与旧服务器相同的集和排序规则。这将确保复制正常进行。您还需要确保数据库、表和列在主从服务器之间都具有相同的排序规则。迁移到新服务器后,您可以使用 5.6 在线架构更改或 percona 工具包中的 pt-online-schema-change 等工具修改设置和排序规则。
我还建议运行 percona 的 pt-table-checksum 以确保您的表在复制或初始导出/导入期间没有分歧。
有关差异影响的更多信息,请参阅此处:
- http://dev.mysql.com/doc/refman/5.6/en/replication-features-charset.html
- utf8_general_ci 和 utf8_unicode_ci 有什么区别
- http://forums.mysql.com/read.php?103,187048,188748#msg-188748
- http://dev.mysql.com/doc/refman/5.6/en/charset-unicode-sets.html
- https://dba.stackexchange.com/questions/8006/whats-the-differences- Between-utf8-general-ci-and-utf8-unicode-ci-and-utf8-bina
对于任何使用 Amazon RDS 的人,请记住默认 mysql 5.6 设置使用混合 utf8(mb3) 和 latin1(用于服务器和数据库)。如果从非 RDS 到 RDS 或从 RDS 进行复制(匹配源/目标服务器),您应该使用自定义参数组覆盖这些参数。