我有大量数据文件要处理并存储在远程数据库中。数据文件的每一行代表数据库中的一行,但在插入数据库之前必须格式化。
我的第一个解决方案是通过编写bash脚本处理数据文件并生成SQL数据文件,然后将转储的SQL文件导入数据库。这个解决方案似乎太慢了,正如您所看到的,它涉及创建中间 SQL 文件的额外步骤。
我的第二个解决方案是编写 bash 脚本,在处理数据文件的每一行时,创建 INSERT INTO ...
语句并将 SQL 语句发送到远程数据库:
回显 sql_statement | psql -h remote_server -U 用户名 -d 数据库
即不创建 SQL 文件。但是,此解决方案有一个主要问题,我正在寻找相关建议:
每次我都必须重新连接到远程数据库才能插入一行。
有没有一种方法可以连接到远程数据库,保持连接状态,然后“通过管道”或“发送”insert-SQL 语句,而无需创建巨大的 SQL 文件?
最佳答案
回答您的实际问题
是。您可以使用 named pipe而不是创建文件。考虑以下演示。
在我的数据库 event
中创建一个模式 x
用于测试:
-- DROP SCHEMA x CASCADE;
CREATE SCHEMA x;
CREATE TABLE x.x (id int, a text);
像这样从 shell 创建命名管道 (fifo):
postgres@db:~$ mkfifo --mode=0666 /tmp/myPipe
1) 在服务器上使用命名管道调用 SQL 命令COPY
:
postgres@db:~$ psql event -p5433 -c "COPY x.x FROM '/tmp/myPipe'"
这将在数据库中的表 x.x
上获得一个独占锁。连接保持打开状态,直到 fifo 获取数据。小心不要让它打开太久!您可以在填充管道后调用它,以最大限度地减少阻塞时间。您可以选择事件的顺序。一旦两个进程绑定(bind)到管道,该命令就会执行。第一个等待第二个。
或者2)您可以从管道在客户端执行SQL:
postgres@db:~$ psql event -p5433 -f /tmp/myPipe
这更适合您的情况。此外,在执行 SQL 之前,不会锁定任何表。
Bash 将被阻止。它正在等待管道的输入。要从一个 bash 实例完成所有操作,您可以将等待进程发送到后台。像这样:
postgres@db:~$ psql event -p5433 -f /tmp/myPipe 2>&1 &
无论哪种方式,从同一个 bash 或不同的实例,您现在都可以填充管道。
变体 1) 的三行演示:
postgres@db:~$ echo '1 foo' >> /tmp/myPipe; echo '2 bar' >> /tmp/myPipe; echo '3 baz' >> /tmp/myPipe;
(小心使用制表符作为分隔符或指示 COPY 使用 WITH DELIMITER 'delimiter_character'
接受不同的分隔符)
这将触发带有 COPY 命令的挂起的 psql 执行并返回:
COPY 3
变体 2) 的演示:
postgres@db:~$ (echo -n "INSERT INTO x.x VALUES (1,'foo')" >> /tmp/myPipe; echo -n ",(2,'bar')" >> /tmp/myPipe; echo ",(3,'baz')" >> /tmp/myPipe;)
INSERT 0 3
完成后删除命名管道:
postgres@db:~$ rm /tmp/myPipe
检查是否成功:
event=# select * from x.x;
id | a
----+-------------------
1 | foo
2 | bar
3 | baz
上面代码的有用链接
Reading compressed files with postgres using named pipes
Introduction to Named Pipes
Best practice to run bash script in background
你可能需要也可能不需要的建议
对于批量 INSERT
,您有比单独的 INSERT 更好的解决方案每行。使用此语法变体:
INSERT INTO mytable (col1, col2, col3) VALUES
(1, 'foo', 'bar')
,(2, 'goo', 'gar')
,(3, 'hoo', 'har')
...
;
将您的语句写入文件并执行大量INSERT
,如下所示:
psql -h remote_server -U username -d database -p 5432 -f my_insert_file.sql
(5432 或数据库集群正在监听的任何端口)
my_insert_file.sql
可以包含多个 SQL 语句。事实上,像这样恢复/部署整个数据库是很常见的做法。咨询manual about the -f
参数,或者在 bash 中:man psql
。
或者,如果您可以将(压缩的)文件传输到服务器,您可以使用 COPY 更快地插入(解压缩的)数据。
您还可以在 PostgreSQL 中进行部分或全部处理。为此,您可以COPY TO
(或INSERT INTO
)一个临时表并使用纯SQL 语句准备并最终插入/更新您的表。我经常这样做。请注意,临时表随 session 而生死。
您可以使用类似 pgAdmin 的 GUI舒适的处理。 SQL 编辑器窗口中的 session 保持打开状态,直到您关闭该窗口。 (因此,临时表会一直存在,直到您关闭窗口。)
关于database - 通过命令行插入 SQL 语句而无需重新打开与远程数据库的连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7849232/