【问题标题】:Convert huge database from Latin1 to UTF8?将庞大的数据库从 Latin1 转换为 UTF8?
【发布时间】:2013-06-06 00:08:21
【问题描述】:

我们有一个用 PHP 编写的系统,这些年来它已经变得相当庞大。数据库是 MySQL(InnoDB 表),目前有超过 12GB 的数据,有数百个表,其中许多有超过 1200 万条记录!

问题是,很多表/列(但不是全部)都在 latin1 中,我们(显然)在存储外来字符时遇到了问题。

我们将所有表格/文本列转换为 UTF8 且停机时间尽可能短的最佳方式是什么?

该系统有数百人 24/7 全天候使用,因此长时间停机确实不是一种选择。

有没有任何方法可以在没有大量停机时间的情况下成功地做到这一点,有什么明显的事情需要我们注意吗?

我知道我们需要设置以下内容以使我们的应用程序使用 utf-8:

  • <meta http-equiv="content-type" content="text/html; charset=utf-8" />
  • ini_set('default_charset', 'utf-8');
  • SET NAMES utf8
  • 上传文件之前在我们的 IDE 中编码为 UTF8 的文件

我阅读了其他各种帖子,但似乎每个人都在建议不同的方法,有些人说它需要完整的数据库转储/恢复......这意味着停机时间会持续数小时。

那么最好的方法是什么?

【问题讨论】:

  • 您是否尝试阅读此问题:stackoverflow.com/questions/2543993/…
  • 我在问是否有任何方法可以在不转储和重新导入整个数据库的情况下执行此操作。我猜,完全恢复可能意味着大约 15 小时以上的停机时间。我们有一个备份数据库服务器,我们将所有内容复制到该服务器。我正在寻找比超过 15 小时的停机时间更好的解决方案,也许是一些巧妙的复制想法,使我们的备份副本变成 UTF8,这样我们就可以切换等等。
  • 您可以使用alter table tablename convert to charset utf8 一次转换一个表格。对于较小的表,这应该相当快,因此您可以在数据库运行的情况下执行此操作,因此只有具有数百万条记录的大表才是问题。
  • @Joni:12GB 是 12 十亿 字节,所以在这种情况下,平均记录大小约为 1KB。
  • @MichaelMadsen 你当然是对的,现在说得通了。

标签: php mysql utf-8 character-encoding latin1


【解决方案1】:

您希望做一些可能的事情,但非常困难,也很冒险。放弃聪明:没有什么神奇的东西可以让这一切变得简单。一方面,您要在停机时间与劳动力成本和数据丢失风险之间进行权衡。如果您停机 15 小时,您的人工成本可能会高出十倍。

是否可以为每个表编写一个SELECT 查询,以保证检索自特定日期/时间以来添加或更改的每一行,并且这样做很快?如果是这样,请为每个表编写此查询并将其放在手边。如果没有,则不能使用此方法。

您可以逐表执行此操作。

小桌子不会做太多事情;您可能可以在您的应用程序在非高峰时间运行时执行它们。只需转换列。

如果您从未更新过较大的表,您可以使用所需的字符集和相关列的默认排序规则创建这些表的副本。然后您可以使用INSERT ... SELECT 复制数据。 (http://dev.mysql.com/doc/refman/5.1/en/insert-select.html) 最后,在停机片刻之后,您可以重命名生产表,然后为新表指定生产表名称。您可能需要以几千行为单位执行此操作,以防止 InnoDB 的事务完整性系统耗尽服务器的 RAM。

最后,您必须处理大而多变的桌子。再次,使用INSERT ... SELECT 复制表,再次以 InnoDB 事务不会暂停应用程序操作或耗尽 RAM 的方式。此处的目的是在某个日期/时间对您的表格进行快照。

然后,关闭生产。使用方便的查询选择自开始时间以来所有插入和更改的行,并将它们插入/更新到目标表中。然后重命名您的生产表,并为您的目标表指定生产表的名称,然后重新开始生产。您应该能够相当快地做到这一点。

如果我是你,我会为你的现场制作数据库制作一个临时副本,并在现场制作之前排练此过程的每个步骤。例如,您将在 InnoDB 中遇到外键约束问题;您需要能够仔细处理这些问题。

实际上,如果我是你,我不会尝试这样做。这就像在飞机飞行时更换飞机的发动机。会出什么问题? :-) 相反,我会招致预定的 Web 应用程序停机时间来完成此转换。即使在这种情况下,您也应该在上线之前在登台服务器上尝试整个过程。

【讨论】:

  • 好的,这是有道理的,所以如果我选择更安全的选择,只需休息一下。这样做的正确方法是什么?我现在只是在我们的测试服务器上尝试使用此问题中的方法大致了解停机时间:stackoverflow.com/questions/2543993/… 但我遇到了一些奇怪的问题,它需要 ages (到目前为止超过 10 分钟)删除单个表,以便它可以重新导入数据......在 Ubuntu Server 12.04 上使用 MySQL 5.5.29。
  • 听起来你应该禁用约束(在你的登台服务器上)。试试SET FOREIGN_KEY_CHECKS = 0;
猜你喜欢
  • 2010-11-29
  • 1970-01-01
  • 2016-07-13
  • 2020-01-26
  • 2015-04-09
  • 2011-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多