MySQL数据库从一台服务器迁移到另一台服务器,看起来只是把数据库导出,再导入新的MySQL实例,但真正的风险往往发生在“数据已经导入成功”之后。数据库能够启动,并不代表应用一定能够正常运行。字符集、排序规则、MySQL版本、SQL模式、权限、认证插件、存储引擎、表名大小写、存储过程、触发器、事件、时区以及查询执行计划,都可能因为服务器环境变化而产生兼容问题。
因此,数据库迁移不能只检查“数据有没有过去”,还应该检查“目标服务器是否能够以与原服务器相同的方式解释、访问和处理这些数据”。
第一项需要检查的是MySQL版本。迁移前应该分别记录源服务器和目标服务器的MySQL版本、发行系列以及关键配置。如果只是同一大版本内的服务器迁移,通常兼容性问题相对少一些;如果同时从旧版本迁移到新版本,实际上就已经包含了升级问题。
MySQL官方也建议,在进行版本升级时,先在独立的新服务器上导入生产数据库的结构定义,检查是否存在错误,然后再导入数据进行测试。这样可以在正式切换以前发现存储对象和SQL语法方面的兼容问题。
例如可以先导出数据库对象定义:
mysqldump --all-databases --no-data --routines --events > dump-defs.sql
然后在目标服务器测试导入。如果出现存储过程、事件、表结构或者其他对象创建失败,就应该先解决这些问题,而不是等生产环境切换以后再排查。
字符集和排序规则是第二个非常容易被忽略的地方。MySQL的字符集并不只有数据库这一层,服务器、数据库、表、列以及客户端连接都可能拥有自己的字符集和排序规则。
尤其需要注意一个历史遗留问题:MySQL中的utf8实际上对应旧的utf8mb3,只能覆盖Unicode基本多文种平面,而utf8mb4才能完整支持包括许多Emoji在内的补充字符。MySQL当前文档已经将utf8mb3列为弃用字符集,并建议尽可能使用utf8mb4。
因此,不能看到目标服务器默认使用utf8mb4,就认为整个数据库已经自动完成了转换。数据库默认字符集、表默认字符集和具体列的字符集是不同层级的配置。ALTER DATABASE修改的是数据库默认值,并不会自动把已经存在的表和列全部转换。迁移前应该检查实际表结构,例如:
SHOW CREATE DATABASE database_name;
SHOW CREATE TABLE table_name;
同时还应该检查应用连接使用的字符集。MySQL官方文档明确指出,字符集不仅影响数据存储,也影响客户端与服务器之间的通信。
排序规则更加容易造成“数据没有丢,但结果变了”的问题。例如大小写、重音符号以及字符串比较方式发生变化,都可能影响ORDER BY、GROUP BY、唯一索引以及字符串比较结果。因此,如果目标服务器的默认collation发生变化,不应该仅仅测试页面能不能打开,还应该针对关键查询进行实际验证。
第三项是SQL mode和服务器级参数。很多迁移故障并不是数据本身的问题,而是目标服务器对SQL语句的执行规则发生了变化。
迁移前应该记录至少以下信息:
SELECT VERSION();
SELECT @@sql_mode;
SHOW VARIABLES LIKE 'character_set%';
SHOW VARIABLES LIKE 'collation%';
SHOW VARIABLES LIKE 'time_zone';
SHOW VARIABLES LIKE 'lower_case_table_names';
其中lower_case_table_names尤其需要注意。Linux服务器上的MySQL与某些Windows环境在表名大小写处理方面可能存在差异。如果应用代码中混用了Users、users和USERS这样的表名,在迁移操作系统以后可能出现原服务器正常、目标服务器找不到表的问题。
时区也不能遗漏。如果应用大量使用TIMESTAMP、DATETIME以及服务器时间函数,迁移以后服务器系统时区、MySQL时区和应用程序时区不一致,可能造成订单时间、日志时间、定时任务和报表数据出现偏差。
存储引擎是另一个需要实际检查的项目。现代应用通常大量使用InnoDB,但老系统中仍可能存在MyISAM、MEMORY或者其他特殊表。不同存储引擎的事务、锁、崩溃恢复和并发行为不同,不能在迁移时未经测试就全部转换。
如果确实需要把MyISAM转换成InnoDB,也应该先确认应用是否依赖原来的行为,然后单独测试,而不是把“全部转换成InnoDB”作为所有迁移项目的固定步骤。
对于InnoDB数据库,使用逻辑备份迁移通常比直接复制数据目录更加稳妥。MySQL官方说明,mysqldump --single-transaction通过事务一致性读取来导出InnoDB数据,在适当条件下可以避免长时间锁住应用表;但这个选项只保证事务型表的一致性,对于MyISAM和MEMORY等非事务表并不提供同样的保证。
典型的InnoDB逻辑备份可以使用:
mysqldump \
--single-transaction \
--quick \
--routines \
--events \
--triggers \
database_name > database.sql
这里还要注意,--single-transaction并不意味着“整个生产数据库在任何情况下都完全冻结”。导出期间如果对正在读取的表执行某些DDL,例如ALTER TABLE、DROP TABLE、TRUNCATE TABLE等,可能影响一致性或者导致导出失败。MySQL官方对此有明确说明。
数据库对象也不能只看表。完整迁移时,还应该检查VIEW、TRIGGER、PROCEDURE、FUNCTION、EVENT以及其他应用依赖的对象。很多网站迁移以后发现“页面能打开,但是定时任务不工作”或者“订单写入以后某些字段没有自动更新”,最后才发现EVENT或者TRIGGER没有正确迁移。
存储过程和函数尤其需要检查,因为它们可能依赖SQL mode、字符集、权限以及特定版本的语法。MySQL官方也提醒,如果修改数据库默认字符集或排序规则,使用这些默认值的已有存储程序可能需要重新创建。
权限迁移同样不能简单复制mysql系统库。不同MySQL版本的账户认证和权限实现可能存在差异,尤其是在从较老版本迁移到MySQL 8.x时,更应该重新检查账户和认证插件。
迁移前可以保存关键账户的权限:
SHOW GRANTS FOR 'app_user'@'localhost';
然后在目标服务器重新创建对应账户并恢复所需权限。不要为了省事直接给应用账号ALL PRIVILEGES ON *.*,更不要把生产服务器上的root账户直接作为网站程序的数据库账户。
如果应用从localhost改成远程连接,还必须重新检查'user'@'host'这一层面的匹配关系。MySQL账户不仅由用户名组成,host部分同样参与账户匹配。因此,即使用户名和密码完全相同,连接来源发生变化以后,也可能出现Access denied。
认证插件也应该进行验证。目标服务器如果采用不同的默认认证机制,而旧版应用使用的PHP、Java、Python、Node.js或其他数据库驱动版本过老,就可能出现数据库本身正常、应用却无法登录的问题。因此数据库迁移完成后必须进行真实的应用连接测试,而不能只用命令行客户端测试一次。
网络连接参数同样需要修改。应用配置中的数据库主机名、IP地址、端口、Unix socket、TLS/SSL参数、用户名和密码,都应该在切换前确认。
如果应用以前连接:
localhost
迁移以后变成:
10.0.0.25
那么这不仅仅是修改一个IP地址,还可能意味着连接方式从Unix socket变成TCP/IP,并因此受到防火墙、bind-address、DNS、TLS和MySQL账户host匹配规则的影响。
索引和查询性能则属于迁移以后最容易被忽略的问题。数据完整地导入目标服务器,并不意味着查询执行计划一定完全相同。如果MySQL版本、统计信息、索引定义、字符集、排序规则或者服务器参数发生变化,优化器可能选择不同的执行计划。
因此,迁移后应该对核心SQL进行基准测试:
EXPLAIN SELECT ...
对于MySQL较新的版本,还可以根据实际需要使用EXPLAIN ANALYZE观察实际执行情况。重点检查订单查询、后台列表、搜索、分页、JOIN以及高频统计SQL,而不是简单执行几条SELECT COUNT(*)就宣布迁移完成。
统计信息也可能影响优化器决策。必要时可以对关键表执行:
ANALYZE TABLE table_name;
但也不应该把ANALYZE TABLE理解成“迁移后所有表必须执行一次”的固定动作,而应该根据实际查询计划和统计信息情况决定。
分区表尤其应该单独验证。迁移以后需要确认分区定义、分区数量、分区键以及关键查询是否保持预期行为。对于大型数据库,还应该检查表空间、磁盘容量、文件系统和I/O性能,而不是只看数据库目录是否成功复制。
备份策略也是迁移的一部分。真正可靠的迁移不是“旧服务器数据已经导入新服务器”,而是新服务器已经可以恢复,而且旧服务器在切换后仍然保留一段时间作为回退方案。
对于关键业务,可以先在测试服务器完整恢复备份,然后验证表数量、关键表行数、关键业务数据以及应用功能。订单、支付金额、用户账户、文章数量、库存和日志等关键数据应该进行针对性检查。
如果使用复制或者基于binlog的增量迁移,还需要验证复制延迟、错误状态、GTID以及最终切换时的数据追平情况。不能因为目标服务器已经开始复制,就认为切换一定安全。
大型数据库通常更适合采用“全量复制+增量同步”的方式。先把历史数据复制到目标服务器,再利用binlog持续同步新增和修改的数据,最后在业务低峰期暂停写入、等待目标端追平,然后切换应用连接。这样可以显著缩短最终停机窗口。
对于小型网站,则没有必要为了追求所谓“专业”而强行上复杂的迁移架构。如果数据库只有几个GB或者几十GB,经过测试的mysqldump逻辑备份、恢复和短暂停机切换可能反而更加简单可靠。真正重要的是提前做一次完整演练。
最终切换以后,还需要观察数据库错误日志、慢查询、连接数、CPU、内存、磁盘I/O以及应用日志。特别要注意迁移前正常、迁移后突然增加的SQL错误和慢查询。数据库迁移最危险的情况往往不是立即报错,而是表面上一切正常,几个小时以后才发现某类请求开始变慢或者某个定时任务没有执行。
因此,一次完整的MySQL迁移应该至少经过“环境盘点、版本兼容测试、结构导出测试、数据恢复测试、应用连接测试、核心SQL性能测试、备份恢复测试、正式切换和回退验证”几个阶段。
数据库迁移真正需要解决的并不是“怎么把SQL文件搬过去”,而是让新服务器在数据、权限、SQL行为、应用连接和性能方面都能够正确接替旧服务器。只要把迁移理解成一次完整的运行环境切换,而不是简单的数据复制,很多迁移以后才暴露出来的问题,其实都可以在正式切换之前发现。
MySQL 数据库迁移到另一台服务器,需要注意哪些兼容问题
图片说明:示意图 图片来源:Public Domain(公有领域)
喜欢这篇报道?
使用下面的功能,方便以后继续阅读和分享 MNewsTV
关于文章收藏
收藏不需要注册帐号,收藏信息仅保存在当前浏览器中。
删除收藏请进入「我的收藏」进行管理。
捐助(Paypal): https://www.paypal.me/observeccp 订阅中国观察电报 Telegram : https://t.me/s/ObserveCCP