Вставка операторов SQL через командную строку без повторного открытия соединения с удаленной базой данных - PullRequest
12 голосов
/ 21 октября 2011

У меня есть большое количество файлов данных для обработки и хранения в удаленной базе данных.Каждая строка файла данных представляет собой строку в базе данных, но должна быть отформатирована перед вставкой в ​​базу данных.

Моим первым решением было обработать файлы данных, написав сценарии bash и создав файлы данных SQL, а затем импортироватьсбросить файлы SQL в базу данных.Это решение кажется слишком медленным и, как вы можете видеть, включает в себя дополнительный этап создания промежуточного файла SQL.

Мое второе решение заключалось в написании сценариев bash, которые при обработке каждой строки файла данных создают и INSERT INTO ... оператор и отправляет оператор SQL в удаленную базу данных:

echo sql_statement | psql -h remote_server -U username -d database

т.е. не создает файл SQL.Это решение, однако, имеет одну серьезную проблему, по которой я ищу совет:
Каждый раз, когда мне приходится повторно подключаться к удаленной базе данных, чтобы вставить одну строку.

Есть лиспособ подключиться к удаленной базе данных, оставаться на связи, а затем «передать» или «отправить» оператор вставки SQL без создания огромного файла SQL?

Ответы [ 2 ]

19 голосов
/ 21 октября 2011

Ответ на ваш актуальный вопрос

Да .Вы можете использовать именованный канал вместо создания файла.Рассмотрим следующую демонстрацию.

Создать схему x в моей базе данных event для тестирования:

-- DROP SCHEMA x CASCADE;
CREATE SCHEMA x;
CREATE TABLE x.x (id int, a text);

Создать именованный канал (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 не получит данные.Будьте осторожны, не оставляйте это открытым слишком долго!Вы можете назвать это после , когда вы заполнили трубу, чтобы минимизировать время блокировки.Вы можете выбрать последовательность событий.Команда выполняется, как только два процесса связываются с каналом.Первый ждет второго.

или 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')
Это вызоветожидающий psql с командой COPY для выполнения и возврата:

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

Полезные ссылки для кода выше

Чтение сжатых файлов с использованием postgres с использованием именованных каналов
Введение в именованные каналы
Лучшая практика запуска bash-скрипта в фоновом режиме


Совет, который вам может понадобиться, а может и не понадобиться

Для больших 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 или любой другой порт, который прослушивает db-кластерon)
my_insert_file.sql может содержать несколько операторов SQL.Фактически, это обычная практика - восстанавливать / развертывать целые базы данных подобным образом.Обратитесь к руководству по поводу параметра -f или в bash: man psql.

Или, если вы можете передать (сжатый) файл на сервер, вы можете использовать COPY , чтобы вставить (распакованные) данные еще быстрее.

Вы также можете выполнить часть или всю обработку внутри PostgreSQL.Для этого вы можете COPY TO (или INSERT INTO) временную таблицу и использовать простые операторы SQL для подготовки и, наконец, вставки / обновления ваших таблиц.Я много этим занимаюсь.Помните, что временные таблицы живут и умирают вместе с сеансом.

Вы можете использовать графический интерфейс, например pgAdmin , для удобной работы.Сеанс в окне редактора SQL остается открытым, пока вы не закроете окно.(Следовательно, временные таблицы действуют до тех пор, пока вы не закроете окно.)

1 голос
/ 13 июня 2013

Я знаю, что опаздываю на вечеринку, но почему вы не можете объединить все ваши INSERT утверждения в одну строку с точкой с запятой, отмечающей конец каждого утверждения?(Внимание! Впереди псевдокод ...)

Вместо:

for each line
  sql_statement="INSERT whatever YOU want"
  echo $sql_statement | psql ...
done

Использование:

sql_statements=""
for each line
  sql_statement="INSERT whatever YOU want;"
  sql_statements="$sql_statements $sql_statement"
done
echo $sql_statements | psql ...

Таким образом, вам не нужно ничего создавать на вашемфайловая система, выполняйте кучу перенаправлений, выполняйте любые задачи в фоновом режиме, не забудьте впоследствии удалить что-либо в вашей файловой системе или даже напомнить себе, что такое именованный канал.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...