Heroku Postgres - припинення вивішеного запиту (простою в транзакції)


99

Я використовую Heroku з опцією Crane Postgres, і я запускав запит по базі даних з моєї локальної машини, коли мій локальний автомат вийшов з ладу. Якщо я біжу

select * from pg_stat_activity

один із записів має

<IDLE> in transaction

у стовпці current_query_text.

Як результат, я не можу скинути таблицю, до якої був записаний запит, який було припинено. Я спробував використовувати pg_cancel_backend (N), і він повертає True, але, здається, нічого не відбувається.

Як я можу припинити цей процес, щоб я міг скинути таблицю?


1
Можливо, питання слід перефразувати так: "як я припиняю власний запит, коли немає ні кореневого доступу до сервера постгресів, ні доступу суперпользователя до бази даних". Це здається дуже гарним питанням, і я не знаю відповіді.
tobixen

Відповіді:


138

Це загальна відповідь Постгреса, а не характерна для героїки


(Проста дурна відповідь на це питання може бути ... просто перезапустіть postgresql. Припустимо, що це не бажано чи не є варіантом ...)

Знайдіть PID, запустивши цей sql:

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

(Запит може потребувати коригування залежно від версії постгресів - з часом просто виберіть * з 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" :-)


Тривалий "простой у транзакції" часто означає, що транзакція не була припинена з "фіксацією" або "відкатом", що означає, що додаток є помилковим або не належним чином розроблено для роботи з транзакційними базами даних. Слід уникати тривалого "простою в операції", оскільки це також може спричинити великі проблеми з роботою.


Я намагався pg_cancel_backend безрезультатно. У мене немає доступу до оболонки і я не є суперпользователем, тому не можу надіслати SIGKILL за допомогою pg_terminate_backend
алан

Яку версію Postgres ви використовуєте? (натяк:) select version(). Чи отримуєте ви повідомлення про помилки під час використання pg_cancel_backend?
tobixen

Я зробив спробу використовувати сам pg_cancel_backend, тому отримав повідомлення про помилку "повинно бути надрукованим для того, щоб сигналізувати про інші серверні процеси" ... це означає, що, мабуть, вам знадобиться або кореневий доступ до сервера, або доступ до db через якийсь суперкористувач postgres (тобто користувач postgres ) вбити власний запит. Це, здається, смокче трохи :-(
tobixen

1
виявляється, що процеси були скасовані pg_cancel_backend, але запити все ще відображаються в pg_stat_activity на деякий час
алан

Можливо, це характерно для Хероку. Наскільки я бачу, для звичайних постгресів дійсно потрібно бути надрукованим, щоб знищити застряглий процес (я тестую за допомогою "select pg_sleep (3600);" на pg 8.4, і я отримую "ПОМИЛКА: повинен бути надруковим для сигналу інші серверні процеси "). Хоча, тоді знову "простоювати угоди" не зовсім те саме.
tobixen

36

Спробуйте це:

select pg_terminate_backend(pid int)

Більше про це ви можете дізнатися тут . Це має бути "чистішим" рішенням цієї проблеми, ніж процес вбивства системою.


Будь-ласка, додайте, як отримати підказку до своєї відповіді
гірський альпініст

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. замовити по xact_start і обмежити 1, і я міг би погодитися ... але потім знову, я вважаю за краще переглядати список, перш ніж сліпо вбивати.
tobixen

як що до цього? SELECT pid, pg_cancel_backend(pid) FROM pg_stat_activity WHERE state != 'idle' AND (now() - query_start) > interval '5 minutes';
АФН
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.