Как снять возможные блокировки строк Postgres?

Я выполнил оператор обновления для большой таблицы PostgreSQL через интерфейс phpPgAdmin. Это время истекло, так как оно работало слишком долго.

Теперь я могу обновить некоторые строки из этой таблицы, но не все. Попытка обновить некоторые строки зависнет.

Ряды закрыты? Как разрешить обновление этих строк?


person Liam    schedule 30.06.2009    source источник


Ответы (6)


Какую версию PostgreSQL вы используете? Следующее предполагает 8.1.8 или более позднюю версию (это может относиться и к более ранним версиям, я не знаю).

Я предполагаю, что вы имеете в виду, что время ожидания phpPgAdmin истекло - серверная часть PostgreSQL займет столько времени, сколько потребуется для выполнения запроса/обновления. В этом случае возможно, что исходный сеанс все еще жив и запрос UPDATE все еще выполняется. Я предлагаю выполнить следующий запрос (взято из главы 24 документации PostgreSQL ) на машине, на которой размещен серверный процесс PostgreSQL, чтобы проверить, активен ли сеанс:

ps auxwww|grep ^postgres

Должно появиться несколько строк: 1 для основного процесса postmaster и по 1 для процессов "записи", "буфера статистики" и "сборщика статистики". Все оставшиеся строки предназначены для процессов, обслуживающих соединения с БД. Эти строки будут содержать имя пользователя и имя базы данных.

Надеюсь, из этого вы сможете увидеть, зависает ли еще сеанс, в котором вы выполнили исходное ОБНОВЛЕНИЕ. Хотя теоретически вы можете найти более подробную информацию, SELECT просматривая системное представление pg_stat_activity, по умолчанию PostgreSQL не настроен на заполнение наиболее полезных полей (таких как current_query и query_start). См. главу 24, чтобы узнать, как включить это в будущем.

Если вы видите, что сеанс все еще существует, убейте его. Для этого вам нужно будет войти в систему как пользователь, запускающий процесс (обычно postgres), или root — если вы не запускаете сервер самостоятельно, попросите администратора баз данных сделать это за вас.

И еще: для обновления строк в таблице PostgreSQL не использует блокировки. Вместо этого он позволяет каждой записывающей транзакции создавать новую «версию» БД, которая становится «текущей версией» при фиксации транзакции, при условии, что она не конфликтует с обновлениями, сделанными в то же время другими транзакциями. Так что я подозреваю, что "зависание", которое вы видите, вызвано чем-то другим, хотя чем, я не уверен. (Вы проверили очевидные вещи, например, заполнен ли раздел диска, содержащий БД?)

person j_random_hacker    schedule 30.06.2009
comment
Отлично, это сработало, спасибо. Обратите внимание: когда я убил процесс, вызвавший проблему, это позволило запустить некоторые другие процессы, ожидавшие снятия блокировки. Это вызвало дополнительные проблемы. Я должен был убить процессы, помеченные как WAITING, когда я запускал ps auxwww|grep ^postgres, прежде чем убить первый проблемный процесс. - person Liam; 30.06.2009
comment
Если вы видите, что сеанс все еще существует, убейте его. -- Для новичков посмотрите, где написано postgres 15398 ... idle in transaction или что-то еще, и введите kill 15398 в Putty. - person Noumenon; 31.07.2017

Можно увидеть замки.

Вот представление, которое немного упрощает использование pg_locks напрямую:

CREATE OR REPLACE VIEW public.active_locks AS 
 SELECT t.schemaname,
    t.relname,
    l.locktype,
    l.page,
    l.virtualtransaction,
    l.pid,
    l.mode,
    l.granted
   FROM pg_locks l
   JOIN pg_stat_all_tables t ON l.relation = t.relid
  WHERE t.schemaname <> 'pg_toast'::name AND t.schemaname <> 'pg_catalog'::name
  ORDER BY t.schemaname, t.relname;

Затем вы просто выбираете из представления:

SELECT * FROM active_locks;

И убить его с помощью:

SELECT pg_cancel_backend('%pid%');

Другие решения: http://wiki.postgresql.org/wiki/Lock_Monitoring.

person Chris    schedule 14.04.2014
comment
В Postgres нет представления или таблицы с именем active_locks. Возможно, вы имеете в виду pg_locks? - person a_horse_with_no_name; 14.04.2014
comment
Вы правы, в нашей базе данных был пользовательский вид, я отредактировал ответ. - person Chris; 15.04.2014
comment
В моем случае ваш pg_cancel_backend в сочетании с запросом здесь: stackoverflow.com/a/10317371/301277 позволил мне удалить все забытые замки. Спасибо! - person Thomas Kekeisen; 18.04.2014
comment
чтобы убить тип SELECT pg_cancel_backend(pid) FROM active_locks; вместо - person Gilbou; 20.01.2017
comment
используйте SELECT pg_terminate_backend('pid') для принудительного уничтожения - person Deepak Kumar; 25.01.2017
comment
Когда я запускаю pg_cancel_backend , я получаю сообщение об ошибке: ОШИБКА: недопустимый синтаксис ввода для целого числа: pid - person ; 12.10.2017
comment
Этот ответ спас нашу производственную установку. - person nicholaswmin; 18.03.2019

Просто:

Получить активные блокировки из pg_locks:

выберите t.relname,l.locktype,page,virtualtransaction,pid,mode,предоставленный pg_locks l, pg_stat_all_tables t где l.relation=t.relid порядок по отношению asc;

Скопируйте результат pid (например: 14210) из приведенного выше результата и замените его в приведенной ниже команде.

ВЫБЕРИТЕ pg_terminate_backend('14210')

person chiru    schedule 10.05.2018

Чтобы снять возможные блокировки с Postgres, я обычно выполняю их последовательно.

  1. Найдите длительные запросы в своей БД, выполнив следующий запрос. Это поможет вам получить PID долго выполняющегося запроса, который блокирует ваше обновление.

    SELECT
    pid,
    now() - pg_stat_activity.query_start AS duration,
    query,
    state
    FROM pg_stat_activity
    WHERE (now() - pg_stat_activity.query_start) > interval '5 minutes';
    
  2. или если вы можете узнать, какие процессы удерживают блокировку в конкретной таблице, выполнив этот запрос

    SELECT *
    FROM pg_locks l
    JOIN pg_class t ON l.relation = t.oid AND t.relkind = 'r'
    WHERE t.relname = 'Bill';
    
  3. Как только вы выясните PID, который является «активным» и блокирует ваше обновление, вы можете убить его, выполнив этот запрос. Требуется некоторое время, чтобы убить процесс.

    SELECT pg_cancel_backend(__pid__);
    
  4. Проверьте, запустив запрос 2, если процесс убит. Если он все еще активен, уничтожьте этот процесс, выполнив этот запрос.

    SELECT pg_terminate_backend(__pid__);
    
person Saurabh Saha    schedule 16.03.2019

Это снимет все блокировки со всех таблиц.

SELECT pg_terminate_backend(pid)
    FROM pg_stat_activity
    WHERE pid <> pg_backend_pid();
person Jakobovski    schedule 11.01.2020

я никогда не работал с PostreSql, но если он похож на другие, я бы сказал, что вам нужно убить соединение/завершить транзакцию, удерживающую блокировки.

person Mladen Prajdic    schedule 30.06.2009