#postgresql #deadlock
#postgresql #взаимоблокировка
Вопрос:
ПРИМЕЧАНИЕ: plsh
это язык PostgreSQL, который выполняет команды командной оболочки.
Я пытаюсь вызвать plsh
функцию изнутри plpgsql
функции.
Во-первых, есть более масштабная plpgsql
функция:
CREATE OR REPLACE FUNCTION my_schema.big_function(my_arg character varying)
RETURNS text AS
$BODY$
BEGIN
DROP TABLE IF EXISTS backend.table_B;
CREATE TABLE backend.table_B AS
--Create a table with a SELECT with some joins,
--right now the resulting table is empty
RAISE NOTICE 'table_B created';
PERFORM my_schema.insert_from_shell(my_arg);
RETURN 'Function Ended';
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
Тогда есть plsh
функция:
CREATE OR REPLACE FUNCTION my_schema.insert_from_shell(my_arg character varying)
RETURNS text AS
$BODY$
#!/bin/sh
PGPASSWORD=mypassword psql -d mydatabase -h myhost -p myport -U myuser -c "INSERT INTO myschema.table_A(mycolumn) VALUES('$1')"
$BODY$
LANGUAGE plsh VOLATILE
COST 100;
Когда я пытаюсь выполнить следующее:
SELECT my_schema.big_function('test');
это никогда не заканчивается. С другой стороны, если я прокомментирую PERFORM
строку из первой функции и вызову обе функции по отдельности, каждая из них завершится менее чем за секунду:
SELECT my_schema.big_function('test');
SELECT my_schema.insert_from_shell('test');
Может быть проблема с выполнением plsh
функций изнутри plpgsql
функций, но я не уверен.
Я мог бы обойти это, вызывая обе функции по отдельности, используя скрипт вне базы данных, но я бы предпочел решить это изнутри базы данных и вызвать единственную функцию.
Любой указатель или помощь будут высоко оценены.
Комментарии:
1. Что вы получаете за
SELECT pid, relation::regclass, mode, granted FROM pg_locks;
? Бьюсь об заклад,big_function
выполняется внутри транзакции с операторами, которые блокируютtable_a
.2. Я думаю, вы, возможно, на что-то натолкнулись. Копнув немного глубже, я нашел функцию триггера, связывающую
table_a
иtable_b
. Есть ли способ зафиксировать созданиеtable_a
промежуточной функции?
Ответ №1:
Предполагая, что триггер в транзакции big_function
устанавливает конфликтующую блокировку table_a
, как предложено в комментарии, вы могли бы рассмотреть следующее решение:
Сделайте триггер a CONSTRAINT TRIGGER
(тогда это должен быть AFTER
триггер) и объявите его как DEFERRABLE INITIALLY DEFERRED
. Тогда он не будет выполняться правильно, когда запускающий оператор выполняет, но будет отложен до COMMIT
в конце транзакции.
К тому времени insert_from_shell
завершится и зафиксируется, поэтому взаимоблокировки не будет.
Комментарии:
1. Сейчас я уже ушел из офиса, но я попробую завтра и дам вам знать! Большое спасибо!