Heroku Postgres - завершить зависший запрос (бездействие в транзакции)

99

Я использую Heroku с опцией Crane Postgres, и я выполнял запрос к базе данных с моего локального компьютера, когда мой локальный компьютер вышел из строя. Если я сбегу

select * from pg_stat_activity

одна из записей

<IDLE> in transaction

в столбце current_query_text.

В результате я не могу отбросить таблицу, в которую выполнялась запись прерванным запросом. Я пробовал использовать pg_cancel_backend (N), и он возвращает True, но ничего не происходит.

Как я могу прервать этот процесс и отбросить стол?

Алан
источник
1
Возможно, вопрос следует перефразировать на «как мне завершить свой собственный запрос, если у меня нет ни корневого доступа к серверу postgres, ни доступа суперпользователя к базе данных». Это действительно очень хороший вопрос ... и я не знаю ответа.
tobixen 02

Ответы:

138

Это общий ответ Postgres, а не специфический для героку


(Простой-глупый ответ на этот вопрос может быть ... просто перезапустите postgresql. Предполагая, что это нежелательно или не вариант ...)

Найдите PID, запустив этот sql:

SELECT pid , query, * from pg_stat_activity
  WHERE state != 'idle' ORDER BY xact_start;

(Запрос может потребовать исправления в зависимости от версии postgres - в конце концов, просто выберите * из pg_stat_activity). Вы найдете pid в первом (левом) столбце, а первая (верхняя) строка, скорее всего, будет запросом, который вы хотите завершить. Я предполагаю, что pid - 1234 ниже.

Вы можете отменить запрос через SQL (т.е. без доступа к оболочке), если он принадлежит вам или у вас есть права суперпользователя:

select pg_cancel_backend(1234);

Это «дружественный» запрос на отмену 1234-запроса, и, если повезет, через некоторое время он исчезнет. В конце концов, это более эффективно:

select pg_terminate_backend(1234);

Если у вас есть доступ к оболочке и права root или postgres, вы также можете сделать это из оболочки. Чтобы «отменить» можно:

kill -INT 1234

и "завершить" просто:

kill 1234

НЕ:

kill -9 1234

... это часто приводит к сгоранию всего сервера postgres, тогда вы также можете перезапустить postgres. Postgres довольно надежен, поэтому данные не будут повреждены, но я бы не рекомендовал использовать «kill -9» в любом случае :-)


Длительное «бездействие в транзакции» часто означает, что транзакция не была завершена с помощью «фиксации» или «отката», что означает, что приложение содержит ошибки или неправильно спроектировано для работы с транзакционными базами данных. Следует избегать длительного "простоя в транзакции", так как это также может вызвать серьезные проблемы с производительностью.

Tobixen
источник
Я пробовал pg_cancel_backend безрезультатно. У меня нет доступа оболочки , и я не суперпользователь , так что я не могу отправить SIGKILL с помощью pg_terminate_backend
алан
Какую версию postgres вы используете? (подсказка:) select version(). Вы получаете сообщения об ошибках при использовании pg_cancel_backend?
tobixen 02
Я сам пытался использовать pg_cancel_backend, поэтому получил сообщение об ошибке «должен быть суперпользователем, чтобы сигнализировать другим серверным процессам» ... означает, что, по-видимому, вам понадобится либо root-доступ на сервере, либо доступ к базе данных через какого-то суперпользователя postgres (т.е. пользователя postgres ), чтобы убить свой собственный запрос. Кажется, это немного отстой :-(
tobixen 02
1
оказывается, что процессы были отменены pg_cancel_backend, но запросы все еще отображаются в pg_stat_activity какое-то время
alan
Возможно, это характерно для Heroku. Насколько я могу видеть, в обычных postgres действительно необходимо быть суперпользователем, чтобы убить застрявший процесс (я тестирую с помощью "select pg_sleep (3600);" на стр. 8.4, и получаю "ОШИБКА: должен быть суперпользователь, чтобы сигнализировать другие серверные процессы »). Хотя, опять же, «простоя в транзакции» - это не совсем то же самое.
tobixen
36

Попробуй это:

select pg_terminate_backend(pid int)

Подробнее об этом можно прочитать здесь . Это должно быть «более чистое» решение этой проблемы, чем уничтожение процесса системой.

евгенек
источник
Пожалуйста, добавьте к своему ответу, как получить свой
mountainclimber
19

Вы можете установить heroku-pg-extras надстройку и выполнить следующую команду, чтобы получить PID:

heroku pg:locks --app <your-app>

Тогда просто сделайте:

heroku pg:kill <pid> --app <your-app> 

НОТА : --forceпараметр может использоваться для выдачи pg_terminate_backend, который удаляет все соединение для этого запроса.

Если heroku pg:locks ничего не перечисляет, попробуйте heroku pg:ps.

Для получения дополнительной информации посетите:
https://devcenter.heroku.com/articles/heroku-postgresql#pg-ps-pg-kill-pg-killall

Дэвид Франциско
источник
Спасибо. Я все еще не могу завершить транзакцию / PID ... мой компьютер завис в оборудовании во время импорта, и я не могу завершить PID. :(
dimitarvp
-3

Мы можем использовать следующее, чтобы добиться этого в одном запросе:

SELECT pg_cancel_backend(pid), pg_terminate_backend(pid) FROM pg_stat_activity WHERE state != 'idle';
кодеры
источник
это убьет все запущенные запросы, тогда можно также перезапустить postgres. order by xact_start и limit 1, и я мог бы согласиться ... но опять же, я бы предпочел посмотреть список, прежде чем убивать вслепую.
tobixen
как насчет этого? SELECT pid, pg_cancel_backend(pid) FROM pg_stat_activity WHERE state != 'idle' AND (now() - query_start) > interval '5 minutes';
AFN