1

以下命令运行良好

$ 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这个命令的输出?我希望输出将是压缩的 CSV 字符串,通过gzip.

下面的命令有效,例如:

$ 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В�,Д���}������+��

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

4

4 回答 4

2

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

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

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

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

于 2021-03-19T12:46:47.203 回答
2

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

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

目前有一个本地网络压缩补丁正在开发中,但是否会制作 v14.

除此之外,你目前无法得到你想要的。

于 2021-03-19T12:50:14.097 回答
1

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

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 到 db 服务器,也许您有 ssh 到同一数据中心中的另一个盒子,该盒子具有到 db 服务器的快速网络链接,在这种情况下,您可以 ssh 到它而不是 db 服务器。数据将在该盒子和数据库之间未压缩地传输,在盒子上压缩,并通过 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 选项。

于 2021-03-19T14:24:54.267 回答
-1

您可以使用复制到程序:

COPY foo_table to PROGRAM 'gzip > /tmp/foo_table.csv' delimiters',' CSV HEADER;
于 2021-03-19T11:42:46.807 回答