Featured image of post PostgreSQL Docker 实战:扩展生态、TimescaleDB 时序插件与 mysql2pg 迁移

PostgreSQL Docker 实战:扩展生态、TimescaleDB 时序插件与 mysql2pg 迁移

PostgreSQL 9.6 / 17.5 容器化部署、All-in-one 扩展矩阵(pgvector / TimescaleDB / ParadeDB / pg_duckdb)、pgloader 从 MySQL 迁移到 PostgreSQL——把 PG 在容器化场景下的最佳实践一次性说清

PostgreSQL 9.6(2016)开始支持并行查询FDW 联邦查询;PG 10 引入了原生表分区、逻辑复制;PG 11/12/13/14/15/16/17 连续在 JSON 索引、SQL/JSON 标准、逻辑复制槽等方向稳步推进。2020 年后,pgvector(向量检索)、TimescaleDB(时序)、ParadeDB(全文检索)、pg_duckdb(OLAP) 让 PostgreSQL 成了"一个数据库覆盖 OLTP + OLAP + 向量 + 时序"的"多模态"基座。这篇文章把 PG 9.6/17.5 的 Docker 化、扩展生态、MySQL 迁移一次性收齐。

阅读对象:考虑从 MySQL 迁到 PostgreSQL 的团队、需要 AI 时代向量检索、需要时序与关系混合存储、对 ParadeDB / pg_duckdb 等新扩展感兴趣的同学。 覆盖范围:PostgreSQL 官方镜像 + TimescaleDB HA 镜像启动;All-in-one 扩展矩阵(pgvector / TimescaleDB / ParadeDB / pg_duckdb 4 大扩展的核心场景与价值);pgloader 从 MySQL 迁移到 PostgreSQL 的完整流程;序列重置、超表创建、文本字段扩容等实战。

一、PostgreSQL 在 Docker 里的关键决策

决策选项推荐
镜像官方 postgres / timescale/timescaledb-ha / bitnami/postgresql时序选 TimescaleDB;其他用官方
数据目录/var/lib/postgresql/data默认值
高可用Patroni / 流复制 / 共享存储单实例 Patroni 是主流
备份pg_dump / pg_basebackup / WAL-G大库 WAL-G 流式
迁移pgloader / 自研 ETLpgloader 是事实标准

二、官方 postgres 镜像启动

2.1 拉取与启动

1
2
3
4
5
6
7
8
9
docker pull postgres:17.5
docker pull postgres:9.6.21-alpine   # 旧版兼容

docker run -d \
  --name pg \
  -p 5433:5432 \
  -e POSTGRES_PASSWORD={{REDACTED}} \
  -e PGDATA=/var/lib/postgresql/data/pgdata \
  postgres:17.5

关键参数

  • POSTGRES_PASSWORD:必填,超级用户 postgres 的密码
  • PGDATA:自定义数据目录(避免与挂载点冲突)
  • 默认端口 5432,开发环境用 -p 5433:5432 区分多版本

2.2 TimescaleDB HA 镜像

Timescale 出品的 HA 镜像(基于 Patroni + etcd + PgBouncer):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
docker pull timescale/timescaledb-ha:pg18.4-ts2.27.1

# 镜像内已封装好
# 5432/tcp   - PostgreSQL
# 8008/tcp   - Patroni REST API
# 8081/tcp   - PgBouncer / 监控

mkdir -p /home/docker/postgres/pgdata
chown -R 1000:1000 /home/docker/postgres/pgdata

docker run -d \
  --name pg \
  --restart=always \
  -p 5432:5432 \
  -e POSTGRES_DB=sonarqube \
  -e POSTGRES_PASSWORD={{REDACTED}} \
  -v /home/docker/postgres/pgdata:/home/postgres/pgdata \
  timescale/timescaledb-ha:pg18.4-ts2.27.1

2.3 TimescaleDB 独立镜像

不带 HA 模式,更轻量:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
docker pull timescale/timescaledb:2.20.3-pg17

mkdir -p /home/docker/timescaledb/data
docker run -d --name timescaledb \
  --restart=always \
  -e TZ=Asia/Shanghai \
  -e POSTGRES_PASSWORD={{REDACTED}} \
  -e PGDATA=/var/lib/postgresql/data/pgdata \
  -p 5432:5432 \
  -v /home/docker/timescaledb/data:/var/lib/postgresql/data \
  timescale/timescaledb:2.20.3-pg17

三、All-in-one 扩展矩阵

PG 的真正威力在"一个数据库,多种能力"。下表是常见扩展的对比:

扩展核心场景核心价值与 PG 整合方式
ParadeDB全文检索替代原生 tsvector/tsquery,提供更强大的全文检索(分词、排名、聚合)作为 PG 扩展安装,直接操作 PG 表
pg_duckdb / pg_clickhouse离线 / 实时数据分析复用 DuckDB/ClickHouse 的 OLAP 能力,无需迁移数据即可做高性能分析FDW 形式访问,或直接查询 PG 表
pgvector向量搜索(AI 场景)存储向量、计算余弦/内积/欧式距离,支撑 AI 检索/推荐扩展 PG 数据类型(vector)和索引(ivfflat/hnsw)
TimescaleDB时序数据存储与分析对时序数据做分区、压缩、降采样,优化时序查询性能扩展 PG 的表结构(超表)和时序函数

3.1 启用 TimescaleDB 扩展

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
-- 进入 psql
docker exec -it timescaledb psql -U postgres

-- 创建 schema
CREATE SCHEMA mine;

-- 创建普通表(测点历史数据)
CREATE TABLE "mine"."wps_point_hdata" (
  "id" bigserial NOT NULL,
  "equip_id" int8 NOT NULL,
  "equip_name" varchar(100) NOT NULL,
  "point_id" int8 NOT NULL,
  "point_value" numeric(50,2) NOT NULL,
  "data_time" timestamptz(6) NOT NULL,
  "rule_user_id" int8 NOT NULL,
  PRIMARY KEY ("id", "data_time")
);

-- 转换为超表(hypertable)
SELECT create_hypertable('mine.wps_point_hdata', 'data_time');

**超表(hypertable)**是 TimescaleDB 的核心抽象:对用户看就是一张表,底层自动按时间分区(chunks),写入和查询都自动路由到对应分区。

3.2 启用 pgvector 扩展

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
CREATE EXTENSION IF NOT EXISTS vector;

CREATE TABLE documents (
  id bigserial PRIMARY KEY,
  content text,
  embedding vector(1536)  -- OpenAI ada-002 维度
);

-- 余弦相似度搜索(Top 5)
SELECT id, content, 1 - (embedding <=> '[0.1, 0.2, ...]'::vector) AS similarity
FROM documents
ORDER BY embedding <=> '[0.1, 0.2, ...]'::vector
LIMIT 5;

-- 创建 HNSW 索引(速度比 ivfflat 快 5-10x)
CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops);

3.3 启用 pg_duckdb 做 OLAP

1
2
3
4
5
6
CREATE EXTENSION pg_duckdb;

-- 直接用 DuckDB 引擎查询 PG 表
SELECT region, avg(price)
FROM duckdb.query('SELECT * FROM sales WHERE date > ''2024-01-01''')
GROUP BY region;

pg_duckdb 的杀手锏:无需 ETL,就能在生产 PG 表上跑 DuckDB 的向量化分析引擎。亿级数据秒级响应。


四、从 MySQL 迁移到 PostgreSQL(pgloader)

4.1 pgloader 安装

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Debian/Ubuntu
apt update && apt install -y pgloader
pgloader --version

# 从源码(最新版)
wget https://github.com/dimitri/pgloader/releases/download/v3.6.9/pgloader-bundle-3.6.9.tgz
tar xvf pgloader-bundle-3.6.9.tgz
cd pgloader-bundle-3.6.9
make CL="sbcl --dynamic-space-size 9000" save
cp bin/pgloader /usr/bin/pgloader
chmod +x /usr/bin/pgloader

4.2 MySQL 端准备迁移账号

1
2
3
4
5
-- 在 MySQL 中
CREATE USER 'pg_migrate'@'%' IDENTIFIED WITH mysql_native_password BY '{{REDACTED}}';
GRANT SELECT, RELOAD, SHOW DATABASES, REPLICATION CLIENT ON *.* TO 'pg_migrate'@'%';
GRANT ALL PRIVILEGES ON *.* TO 'pg_migrate'@'%';
FLUSH PRIVILEGES;

防超时设置:

1
2
3
4
5
6
7
SET GLOBAL net_read_timeout = 6000;
SET GLOBAL net_write_timeout = 6000;
SET GLOBAL max_allowed_packet = 128 * 1024 * 1024;
SET GLOBAL wait_timeout = 86400;
SET GLOBAL interactive_timeout = 86400;
SET GLOBAL tmp_table_size = 64 * 1024 * 1024;
SET GLOBAL max_heap_table_size = 64 * 1024 * 1024;

4.3 编写迁移配置 mysql2pg.load

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
LOAD DATABASE
     FROM mysql://pg_migrate:{{REDACTED}}@mysql_host:3306/source_db
     INTO postgresql://postgres:{{REDACTED}}@pg_host:5432/target_db

 WITH include drop,
      create tables,
      create indexes,
      reset sequences,
      downcase identifiers,
      workers = 2,
      concurrency = 2,
      batch rows = 100

 CAST type json to jsonb drop default,
      type datetime to timestamp

 SET work_mem = '512MB', maintenance_work_mem = '2GB';

关键参数

  • include drop:迁移前先 drop 目标表
  • reset sequences:序列从当前最大值 +1 开始(避免主键冲突)
  • downcase identifiers:表名/列名转小写(PG 默认区分大小写)
  • CAST type json to jsonb:MySQL JSON → PG JSONB(更高效)
  • batch rows = 100:每批 100 行(OOM 风险时调小)

4.4 执行迁移

1
2
3
4
5
6
7
8
9
# 试运行(不实际写数据)
pgloader --dry-run mysql2pg.load

# 实际迁移(后台跑)
nohup pgloader mysql2pg.load > migration_log.log 2>&1 &
tail -f migration_log.log

# 大数据量增加 dynamic-space-size
pgloader --dynamic-space-size 9000 -vv mysql2pg.load

4.5 迁移后验证

1
2
3
4
5
6
7
-- 对比记录数
SELECT 'mysql' AS src, count(*) FROM <via_fdw>
UNION ALL
SELECT 'pg' AS src, count(*) FROM <local_table>;

-- 重置序列(pgloader 的 reset sequences 选项会自动做,但保险起见手动)
SELECT setval('users_id_seq', (SELECT max(id) FROM users));

五、PG 9.6 / 17 / 18 选型速查

版本关键特性适合
9.6 (2016)并行查询、FDW、pg_basebackup遗留系统(已 EOL)
14 (2021)SQL/JSON 标准、性能大幅提升主流稳定
15 (2022)MERGE 语句、逻辑复制新功能
16 (2023)性能优化、逻辑复制槽高负载
17 (2024)增量备份、改进 EXPLAIN新项目首选
18 (2025)异步 I/O、UUIDv7实验性

六、扩展阅读

使用 Hugo 构建
主题 StackJimmy 设计