目录
-
- 一、需求背景
- 二、数据导出处理方案
-
- 方案一:通过python代码导出
- [方案二:使用 psql 命令行](#方案二:使用 psql 命令行)
- 方案三:在服务器上使用COPY直接写文件
- [方案四:在 DBeaver 中用"导出结果"](#方案四:在 DBeaver 中用“导出结果”)
- 三、总结
--
一、需求背景
将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 | 临时手动导出、小表 |
⚠️ 上述表格总结,实测前三种导入速度接近。