将具有许多表的大型数据库从 latin1 转换为 utf8mb4

n0n*_*g0n 3 mysql mariadb php

所以这不是一个关于“如何将表从 latin1 转换为 utf8?”的问题。我完全知道这一点并且明白了。我想问的问题是,“如何才能让这种转变在过渡期间尽可能少地痛苦?” 我知道我需要转换每个表上的列,然后在某个时候将 PHP MySQL 连接从 latin1 更改为 UTF8,如果我的数据库是 1 GB,而不是 1 TB,我可以轻松完成所有这些。

使用 MariaDB 10.3,数据库中有大约 600 个表,全部都在 InnoDB 存储引擎下,我想说其中可能有 50 个在 1GB 以上,大约 20 个在 10 或 100 GB 之间。这大约 20 个表的问题在于它们是应用程序本身的核心,而这 20 个表中的 1 个表是发生大量 UTF8 问题的地方(当前为 66GB)。

因此,处理大约 90% 的表基本上不会有停机时间,但最后 10% 的表就很麻烦了。关于我应该采取什么步骤以及按什么顺序有什么建议吗?我一般的想法是这样的......

  1. 将 90% 转换为 utf8mb4
  2. 将 PHP MySQL 连接字符集从 latin1 设置为 utf8mb4
  3. 使用我构建的脚本将剩余表的每一列从 latin1 转换为二进制,然后将二进制转换为 utf8mb4。大概留出...... 3-4小时的停机时间???我们的应用程序是一个非常繁忙的应用程序,3-4 小时的停机时间已经很多了。

有人成功尝试过 Percona 的pt-online-schema-change吗?您认为这对这种情况有帮助吗?

我唯一能想到的另一件事是启动并运行一个新的从属数据库,它是主数据库的新副本,在该从属数据库上进行所有 utf8mb4 更改,然后将从属数据库提升到主数据库。我想我也可以事先转换所有的奴隶,只需在我这样做的时候轮流使用或停止使用它们即可。唯一未知的是如果主设备是 latin1,而从设备都是 utf8mb4,会发生什么情况。所有转换后的数据都很好,但我假设新数据可能是 binlog 中的 latin1 并且与字符集无关?

Bil*_*win 5

在我的上一份工作中,我们每周在比您大得多的表上使用 pt-online-schema-change 进行此类更改或任何其他 ALTER TABLE 更改数百次。我开发了一个内部服务和仪表板,以允许开发人员自行运行架构更改。我知道——这太疯狂了!


对于这么大的表,您必须小心重新启动。如果数据库发生故障转移事件或者运行 pt-online-schema-change 的主机重新启动,则必须重新开始。实际上,我们为 pt-online-schema-change 开发了补丁来保存其状态,因此如果脚本被中断,我们可以从中断处恢复。不幸的是,这些补丁并不公开,我已经离开了那份工作。

至少在screenortmux会话中运行 pt-online-schema-change ,这样您就不必依赖不间断的 ssh 会话。


一张非常大的桌子需要多少时间?它会有所不同,因为 pt-online-schema-change 监视几个性能指标,如果它认为表复制工作负载导致性能下降,它会动态地减慢自身速度。因此,如果您的数据库通常服务于高流量水平,则 pt-online-schema-change 会比数据库空闲时花费更多时间。因此,如果可能的话,在非工作时间安排架构更改是值得的。

大型表可能需要 24 小时以上才能完成架构更改。我想我看到的最长的是4周。这可能是一个非常繁忙的数据库服务器上超过 1TB 的单个表。不幸的是,因为我记得在那种情况下,开发人员认为他们可以放弃索引。一旦他们放弃了它,事实证明他们确实需要该索引来完成某些查询。但花了 4 周时间才进行 alter table 来重新创建删除的索引。由于使用了 pt-online-schema-change,在这 4 周内仍然可以查询该表,但是在没有所需索引的情况下某些查询的性能很差。那很痛苦。

我一直告诉开发人员,出于类似的原因,允许表增长得如此之大是自找麻烦。但他们不听。


pt-online-schema-change 的另一个警告是,由于它必须在开始时创建触发器并在结束时进行重命名,因此它必须在开始和结束时短暂地对表进行独占访问。这意味着如果表上有任何未完成的事务,它会等待独占元数据锁。因此,如果您有长时间运行的查询,甚至是导致事务未提交的短查询,它将在最后阻止启动或重命名。当 pt-online-schema-change 被阻止等待该元数据锁时,它会阻止所有其他查询。这可能会导致严重的问题。

因此,我们找到了一种方法来调用 pt-online-schema-change,并在元数据锁定上设置 2 秒超时。如果它无法在 2 秒内完成其工作,它将停止等待,并且必须重试。这可以防止像我所描述的那样出现长时间的僵局。有时,这意味着 pt-online-schema-change 必须重试多次才能开始或完成。但这比停电要好。

理想情况下,您不会有如此长时间运行的事务,但这取决于您的应用程序代码。可能很难知道是否存在此类情况,或者是哪些代码造成了这些情况。


我现在能想到的最后一个警告是,如果您在任何地方对字符串列进行联接,更改字符集,因此排序规则意味着如果这些联接以前依赖于索引,那么现在就不能了。在您可以将连接表更改为兼容之前,此类连接可能会对性能产生很大的不利影响。这与 pt-online-schema-change 无关,但适用于您用来更改字符集的任何方法。


我希望您升级到 utf8mb4,而不仅仅是 utf8。utf8mb4 正在成为首选字符集,而 utf8(3 字节类型)正在被弃用。


我不确定你提到的复制问题。我建议您不要使用生产数据库来测试它,而是在测试环境中进行测试。我怀疑基于语句的复制会起作用,但我不确定基于行的复制是否会起作用。

  • 我会做一次改变。但我会首先在测试环境中使用其他表进行彻底测试。切勿先对您的生产数据尝试任何不熟悉的程序! (2认同)
  • @n0nag0n - **注意!** `CONVERT TO` 和两步 ALTER 会做不同的事情!执行 `SELECT HEX(col)` 来查看您是否有 id 双重编码的 latin1 或 utf8:http://mysql.rjweb.org/doc.php/charcoll#fixes_for_various_cases (2认同)