PostgreSQL COPY 管道输出到 gzip,然后到 STDOUT

PostgreSQL COPY pipe output to gzip and then to STDOUT

以下命令运行良好

$ psql -c "copy (select * from foo limit 3) to stdout csv header"

# output
column1,column2
val1,val2
val3,val4
val5,val6

但是以下情况不会:

$ psql -c "copy (select * from foo limit 3) to program 'gzip -f --stdout' csv header"

# output
COPY 3

为什么这个命令的输出是 COPY 3?我希望在通过 gzip.

之后,输出将是压缩的 CSV 字符串

下面的命令有效,例如:

$ psql -c "copy (select * from foo limit 3) to stdout csv header" | gzip -f -c

# output (this garbage is just the compressed string and is as expected)
߉T`M�A �0 ᆬ}6�BL�I+�^E�gv�ijAp���qH�1����� FfВ�,Д���}������+��

如何制作单个 SQL 命令,直接 将结果通过管道传输到 gzip 并将压缩字符串发送到 STDOUT

您可以使用复制到程序:

COPY foo_table to PROGRAM 'gzip > /tmp/foo_table.csv' delimiters',' CSV HEADER;

副本是 运行在服务器上使用 gzip,而不是将 STDOUT 从 gzip 转发到客户端。

您可以改用 \copy,这将 运行 在客户端进行 gzip:

psql -q -c "\copy (select * from foo limit 3) to program 'gzip -f --stdout' csv header"

这与您在问题中显示的 gzip 管道基本相同。

当您使用 COPY ... TO PROGRAM 时,PostgreSQL 服务器进程(后端)启动一个新进程并将文件通过管道传输到进程的标准输入。该过程的标准输出丢失。如果被调用程序将数据写入文件或类似文件,则使用 COPY ... TO PROGRAM 才有意义。

如果您的目标是压缩通过网络传输的数据,您可以在连接字符串中使用 sslmode=require sslcompression=on 来使用 SSL network compression feature I built into PostgreSQL 9.2。不幸的是,这已被弃用,大多数 OpenSSL 二进制文件都禁用了该功能。

目前有一个本地网络压缩 patch under development,但是否会生成 v14 值得怀疑。

除此之外,您暂时得不到您想要的

如果目标是压缩副本的输出以使其通过网络传输得更快,那么...

psql "postgresql://ip:port/dbname?sslmode=require&sslcompression=1"

如果启用它应该显示“压缩活动”。不过,这可能需要启用一些服务器配置变量。

或者您可以简单地使用 ssh:

ssh user@dbserver "psql -c \"copy (select * from foo limit 3) to stdout csv header\" | gzip -f -c" >localfile.csv.gz

但是...当然,您需要通过 ssh 访问数据库服务器。

如果您没有连接到数据库服务器的 ssh,也许您可​​以通过 ssh 连接到同一数据中心中的另一个机器,该机器具有连接到数据库服务器的快速网络 link,在这种情况下,您可以通过 ssh 连接到它而不是数据库服务器。数据将在该盒子和数据库之间以未压缩的方式传输,在盒子上压缩,并通过 ssh 传输到您的本地机器。这甚至会在数据库服务器上节省 cpu,因为它不会进行压缩。

如果这不起作用,那么,为什么不将 ssh 命令放入“to program”并让服务器通过 ssh 将其发送到您的机器?您必须设置路由器并打开一个端口,但您可以这样做。当然,您必须找到一种方法将密码放在 ssh 命令行中,这通常是一个很大的禁忌,但也许只是一次。或者直接使用 netcat,不需要密码。

此外,如果您想要速度,请使用 zstd 而不是 gzip。

这里有一个 netcat 的例子。我刚刚测试了它,它起作用了。

在 192.168.0.1 的目标机器上:

nc -lp 65001 | zstd -d >file.csv

在另一个终端:

psql -c "copy (select * from foo) to program 'zstd -9 |nc -N 192.168.0.1 65001' csv header" test

注意 netcat 的 -N 选项。