Как снять возможные блокировки строк Postgres? - PullRequest
32 голосов
/ 30 июня 2009

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

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

Строки заблокированы? Как я могу разрешить обновление этих строк?

Ответы [ 5 ]

74 голосов
/ 14 апреля 2014

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

Вот вид, который делает это немного проще, чем прямое использование 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

20 голосов
/ 30 июня 2009

Какую версию 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 избегает использования блокировок. Вместо этого он позволяет каждой записывающей транзакции создавать новую «версию» БД, которая становится «текущей версией», когда транзакция фиксируется, при условии, что она не конфликтует с обновлениями, сделанными тем временем другими транзакциями. Поэтому я подозреваю, что «зависание», которое вы видите, вызвано чем-то другим, хотя я не уверен. (Вы проверили очевидные вещи, например, заполнен ли раздел диска, содержащий БД?)

13 голосов
/ 10 мая 2018

Simple:

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

выберите t.relname, l.locktype, страницу, виртуальную транзакцию, pid, режим, предоставлено из pg_locks l, pg_stat_all_tables t, где l.relation = t.relid order по отношению asc;

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

SELECT pg_terminate_backend ('14210')

2 голосов
/ 16 марта 2019

Чтобы снять возможные блокировки от 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. Проверьте, запустив Query 2, завершен ли процесс. Если он все еще активен, завершите этот процесс, выполнив этот запрос.

    SELECT pg_terminate_backend(__pid__);
    
0 голосов
/ 30 июня 2009

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

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