postgre数据库大批量快速导出方法总结

目录

--

一、需求背景

将postgres数据库中查询的数据结果,需要导出的本地。涉及到的数据量在百万、千万甚至亿级别,需要快速导出。因此需要测试和验证不同导出方式的效率。

二、数据导出处理方案

方案一:通过python代码导出

使用驱动层面提供的 CopyManager 接口,这个方式支持流式导出,非常高效。性能几乎同psql。。数据流路径:Server → Socket → Python File。

  • 使用 COPY TO STDOUT,流式输出数据块;
  • 不缓存全量结果(不像普通 SELECT);
  • Python 直接边接收边写文件。

💡 换句话说,它几乎是 \COPY 的程序化版本。

如果网络不是瓶颈,性能可以接近命令行。

具体程序代码如下:

python 复制代码
import pandas as pd
import psycopg2

# 数据库连接配置
conn = psycopg2.connect(
    host="10.xx.xx.xx",       # 数据库主机
    port="5432",            # 端口
    database="db",     # 数据库名
    user="pg",       # 用户名
    password="pg"  # 密码
)

# 创建游标
cursor = conn.cursor()

with open('清单.csv', 'w', encoding='utf-8') as f:
    cursor.copy_expert("""
        COPY (
            select id, d_index 
            FROM opena.ws
            WHERE (to_tsvector('simple', t) @@ to_tsquery('simple', array_to_string(ARRAY[
                    'po:*','Epoxy','fiber'],' | '))
                )  -- t 匹配
                or (to_tsvector( 'simple',  array_to_string(array(
                    SELECT jsonb_object_keys(index::jsonb)), ' '))
                     @@ to_tsquery('simple', array_to_string(ARRAY[
                        'po:*','Epoxy','fiber'],' | '))
                    ) -- index匹配
            
        ) TO STDOUT WITH CSV HEADER
    """, f)

# 关闭连接
cursor.close()
conn.close()

方案二:使用 psql 命令行

DBeaver 不行,但 psql 命令行客户端 支持 COPY TO STDOUT。✅\COPY 是 psql 的命令,它在客户端执行,

把服务器返回的数据流写到个人电脑上件。

登录psql客户端,执行具体实例如下:

sql 复制代码
\copy (SELECT id, d_index FROM opena.ws WHERE to_tsvector('simple', t) @@ to_tsquery('simple', array_to_string(ARRAY['po:*','Epoxy','fiber'],' | ')) OR to_tsvector('simple', array_to_string(array(SELECT jso
nb_object_keys(index::jsonb)), ' ')) @@ to_tsquery('simple', array_to_string(ARRAY['po:*','Epoxy','fiber'],' | '))) TO 'D:/Data/清单.csv' WITH (FORMAT CSV, HEADER, ENCODING 'UTF8');

或者命令行中执行实例如下:

shell 复制代码
psql  -h 10.xx.xx.xx -U pg -d open -c "\copy (SELECT id, d_index FROM open.ws WHERE to_tsvector('simple', t) @@ to_tsquery('simple', array_to_string(ARRAY['po:*','Epoxy','fiber'],' | ')) OR to_tsvector('simple', array_to_string(array(SELECT jsonb_object_keys(index::jsonb)), ' ')) @@ to_tsquery('simple', array_to_string(ARRAY['poly:*','Epoxy','fiber'],' | ')) limit 100000) TO 'D:/Data/清单.csv' WITH (FORMAT CSV, HEADER, ENCODING 'UTF8');" 

方案三:在服务器上使用COPY直接写文件

PostgreSQL 服务器的磁盘权限(即数据库用户有 superuser 权限),可以直接写文件。📁 文件将被写到 PostgreSQL 服务器上的指定目录。

⚠️

  • 只有 数据库服务器 能访问这个路径,不是个人电脑的路径。
  • 只有数据库超级用户(postgres)或 pg_read_server_files 角色可以执行服务器端 COPY。

服务器终端执行完整导出脚本实例:

shell 复制代码
#!/bin/bash
# ====== PostgreSQL 高速导出脚本 ======

# ==== 可调参数 ====
DB_HOST="localhost"
DB_USER="postgres"
DB_NAME="open"
OUT_DIR="/sda/out_datalists"
FILENAME="open_po_$(date +%Y%m%d_%H%M).csv"

# ==== 确保输出目录存在 ====
mkdir -p "$OUT_DIR"

# ==== 开始时间 ====
START_TIME=$(date +%s)
START_HUMAN=$(date "+%Y-%m-%d %H:%M:%S")
echo "🚀 导出任务开始:$START_HUMAN"
echo "输出文件:${OUT_DIR}/${FILENAME}"
echo "---------------------------------------------"

export PGPASSWORD='postgres'
# ==== 执行 COPY 导出 ====
psql -h "$DB_HOST" -U "$DB_USER" -d "$DB_NAME" -c "
COPY (
    SELECT id, d_index
    FROM open.ws
    WHERE to_tsvector('simple', t) @@ to_tsquery('simple', array_to_string(ARRAY[
        'po:*','Epoxy','fiber'],' | '))
    OR to_tsvector('simple', array_to_string(array(
        SELECT jsonb_object_keys(index::jsonb)
    ), ' ')) @@ to_tsquery('simple', array_to_string(ARRAY[
        'po:*','Epoxy','fiber'],' | '))
        limit 10
) TO STDOUT WITH (FORMAT CSV, HEADER, ENCODING 'UTF8');" \
> "${OUT_DIR}/${FILENAME}"


# ==== 结束时间 ====
END_TIME=$(date +%s)
END_HUMAN=$(date "+%Y-%m-%d %H:%M:%S")
DURATION=$((END_TIME - START_TIME))

# ==== 输出结果 ====
echo "---------------------------------------------"
echo "✅ 导出完成:${OUT_DIR}/${FILENAME}"
echo "📁 文件信息:"
ls -lh "${OUT_DIR}/${FILENAME}"
echo "🕒 开始时间:$START_HUMAN"
echo "🕒 结束时间:$END_HUMAN"
echo "⏱️  耗时:${DURATION} 秒"

方案四:在 DBeaver 中用"导出结果"

DBeaver 本身不支持 COPY STDOUT,但可以:

  • 直接运行 SELECT ...(不带 COPY);
  • 在结果集窗口中点击 "Export resultset";
  • 选择格式 CSV;
  • 导出到文件。

✅ 适合数据量较小(几万~几十万行);

⚠️ 数据量太大(上 GB)容易卡死或内存溢出。

三、总结

通过实测,理想的copy to会最快,但实际可能因环境差异,总体可能和方案一、方案二效率差不多。具体总结如下表:

方案 描述 数据流路径 性能等级 典型速度(MB/s) 适合场景
1️⃣ Python copy_expert (CopyManager) JDBC/psycopg2 Copy API,流式写文件 Server → Socket → Python File 🥈 几乎同 psql 100~250 MB/s 自动化导出任务
2️⃣ \COPY (psql) 服务器流式传输 → 客户端写文件 Server → Socket → Client Disk 🥈 接近最快 100~300 MB/s 命令行导出、大文件
3️⃣COPY TO '/path/file.csv' PostgreSQL 服务器直接写磁盘 Server → Disk 🥇 最快 300~1000 MB/s 服务器上操作、大文件导出
4️⃣ DBeaver 导出结果集 GUI 缓冲 + JDBC → File Server → JDBC → Memory → File 🥉 最慢 5~30 MB/s 临时手动导出、小表

⚠️ 上述表格总结,实测前三种导入速度接近。

相关推荐
乌鸦乌鸦你的小虎牙3 小时前
qt 5.12.8 配置报错(交叉编译环境)
开发语言·数据库·qt
一只大袋鼠3 小时前
Redis 安装+基于短信验证码登录功能的完整实现
java·开发语言·数据库·redis·缓存·学习笔记
Anastasiozzzz3 小时前
深入研究Redis的ZSet底层数据结构:从 Ziplist 的级联更新到 Listpack 的完美救场
数据结构·数据库·redis
菠萝蚊鸭3 小时前
x86 平台使用 buildx 基于源码构建 MySQL Wsrep 5.7.44 镜像
数据库·mysql·galera·wsrep
沙漏无语6 小时前
(二)TIDB搭建正式集群
linux·数据库·tidb
姚不倒6 小时前
三节点 TiDB 集群部署与负载均衡搭建实战
运维·数据库·分布式·负载均衡·tidb
隔壁小邓6 小时前
批量更新方式与对比
数据库
数据知道6 小时前
MongoDB复制集架构原理:Primary、Secondary 与 Arbiter 的角色分工
数据库·mongodb·架构
人道领域6 小时前
苍穹外卖:菜品新增功能全流程解析
数据库·后端·状态模式
修行者Java6 小时前
(七)从 “非结构化数据难存储” 到 “MongoDB 灵活赋能”——MongoDB 实战进阶指南
数据库·mongodb