从 MySQL 中导出数据

忽略表结构(因为我会一开始就在 pg 中创建好)

mysqldump -h <mysql host> -u <mysql user> --password=<mysql password> <mysql database> \
 --skip-disable-keys --skip-add-locks \
 --no-create-info --skip-add-drop-table \
 --set-gtid-purged=OFF --skip-set-charset \
 --where="created_time < '2025-10-01 00:00:00'" \
 <table name> > xxxx.sql

解释:

  • --password=<mysql password>:指定对应的密码。注意:在命令行输入密码有一定的安全风险,通常建议不写在命令行中,让 mysqldump 提示输入,正常情况下应该写 -p
  • --skip-disable-keys:导出数据时不会在导入时禁用和启用索引,适合导入较快,但可能导致导入期间索引不可用。
  • --skip-add-locks:不在导出中包含锁表的 SQL 语句,加快导出速度。PS:不知道是不是真的有用,反正我看到生成的 SQL 还是有的
  • --no-create-info:只导出数据(INSERT 语句),不导出表结构(不包含 CREATE TABLE),适合只需要某些数据。
  • --skip-add-drop-table:不在导出中加入 DROP TABLE 语句,避免删除已有表。
  • --set-gtid-purged=OFF:控制是否输出 GTID 相关的语句(在集群环境中使用),这里关闭(不输出)GTID 信息。
  • --skip-set-charset:不加入设置字符集的相关语句,保持导出文件的简洁。
  • --where=:只导出满足条件的行

导出的内容大致如下:

-- MySQL dump 10.13  Distrib 8.4.7, for Linux (x86_64)
--
-- Host: xxxxx    Database: xxxx
-- ------------------------------------------------------
-- Server version	8.0.28
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

--
-- Dumping data for table `xxxxx`
--

INSERT INTO `xxxx` VALUES (xxxx),(xxxx),(xxxxx),(xxxx);
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

-- Dump completed on 2025-10-31  3:45:10

可以注意到他会把很多表的数据集中在一条语句中插入,好像上面哪个选项去掉之后就会变成一条记录一个 insert 语句,但是我比较喜欢当前这样

如果记录实在是太多,一条 insert 也会写不完,会有多条 insert 语句的

导入 PostgreSQL

处理反引号

PostgreSQL 不支持反引号,还好这里只是表名有反引号,所以用 sed 命令去除即可

sed -i 's/`<表名>`/<表名>/g' xxxx.sql

时区

注意 MySQL 的 datetime 是不带时区的,而 PostgreSQL 的 timestamptz 是带时区的,因此要注意一下(我当前因为 MySQL 和 pg 的时区都是 Shanghai 所以还好)

string 类型

  • 字符串中的单引号(’):PostgreSQL 默认不支持反斜杠转义单引号,正确做法:用两个单引号 '' 来表示单引号
  • 字符串中的双引号("):PostgreSQL 并不需要对双引号进行转义,且字符串是用单引号括起来的,双引号在字符串里是普通字符,不需要转义
  • 字符串中的反斜杠(\):PostgreSQL 关于反斜杠的处理说明:
  • 默认情况下,PostgreSQL 的字符串不支持反斜杠作为转义符,除非开启了 standard_conforming_strings = off,否则反斜杠会被当作普通字符处理。
  • 但是如果你要在字符串中插入反斜杠字符,直接写一个反斜杠即可。如果写两个反斜杠,会被解析成两个反斜杠。
  • 比如如果想插入该表情字符 ¯\_(ツ)_/¯,正确写法:
  • 直接写一个反斜杠即可:'¯\_(ツ)_/¯'
  • 如果你使用的是标准字符串字面量,且没有关闭标准符合字符串,建议写成:E'¯\\_(ツ)_/¯',这里的 E 表示启用 C 风格转义,两个反斜杠 \\ 被转义成一个反斜杠。

最后我为了简单,直接在会话的维度开启 standard_conforming_strings = offSET standard_conforming_strings TO off;

所以我先登录到 pg 的控制台,执行上面的语句开启反斜杠的转义字符功能之后,执行 \i <mysql insert sql file> 来执行数据导入