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 临时手动导出、小表

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

相关推荐
帅大大的架构之路2 小时前
mysql批量插入数据如何更快
数据库·mysql
Amber_373 小时前
mysql 死锁场景 INSERT ... ON DUPLICATE KEY UPDATE
数据库·mysql
VX:Fegn08954 小时前
计算机毕业设计|基于springboot + vue敬老院管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
文刀竹肃4 小时前
DVWA -SQL Injection-通关教程-完结
前端·数据库·sql·安全·网络安全·oracle
思成不止于此4 小时前
【MySQL 零基础入门】MySQL 约束精讲(一):基础约束篇
数据库·笔记·sql·学习·mysql
ActionTech5 小时前
SCALE | SQLFlash 在 SQL 优化维度上的表现评估
数据库·sql
老华带你飞5 小时前
建筑材料管理|基于springboot 建筑材料管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·学习·spring
NaiLuo_456 小时前
MySQL基本查询
数据库·mysql
刺客xs6 小时前
MYSQL数据库------多表查询
数据库·mysql