Force drop db, в то время как другие могут быть подключены

104

Мне нужно удалить базу данных из кластера PostgreSQL DB. Как я могу это сделать, даже если есть активные подключения? Мне нужен своего рода -forceфлаг, который будет сбрасывать все соединения, а затем БД.

Как я могу это реализовать?

Я использую в dropdbнастоящее время, но возможны и другие инструменты.

Alex
источник

Ответы:

155

В PostgreSQL * вы не можете удалить базу данных, когда к ней подключены клиенты.

По крайней мере, не с помощью dropdbутилиты, которая является простой оболочкой DROP DATABASEдля запроса к серверу.

Весьма надежный обходной путь выглядит следующим образом:

Подключайтесь к вашему серверу как суперпользователь , используя psqlили другой клиент. Как не использовать базу данных , которую вы хотите отказаться.

psql -h localhost postgres postgres

Теперь, используя простой клиент базы данных, вы можете принудительно удалить базу данных, выполнив три простых шага:

  1. Убедитесь, что никто не может подключиться к этой базе данных. Вы можете использовать один из следующих методов (второй кажется более безопасным, но не мешает соединениям от суперпользователей).

    /* Method 1: update system catalog */
    UPDATE pg_database SET datallowconn = 'false' WHERE datname = 'mydb';
    
    /* Method 2: use ALTER DATABASE. Superusers still can connect!
    ALTER DATABASE mydb CONNECTION LIMIT 0; */
    
  2. Принудительное отключение всех клиентов, подключенных к этой базе данных, используя pg_terminate_backend.

    SELECT pg_terminate_backend(pid)
    FROM pg_stat_activity
    WHERE datname = 'mydb';
    
    /* For old versions of PostgreSQL (up to 9.1), change pid to procpid:
    
    SELECT pg_terminate_backend(procpid)
    FROM pg_stat_activity
    WHERE datname = 'mydb'; */
    
  3. Удалите базу данных.

    DROP DATABASE mydb;

Шаг 1 требует привилегий суперпользователя для 1-го метода и привилегий владельца базы данных для 2-го. Шаг 2 требует привилегий суперпользователя . Шаг 3 требует привилегии владельца базы данных .


* Это относится ко всем версиям PostgreSQL, вплоть до версии 11.


filiprem
источник
Так что я не знаю, что я сделал неправильно, но теперь я даже не могу подключиться к целевой базе данных! Я также не могу отбросить его, поскольку там написано: «База данных обслуживания не может быть удалена»
Мэтт Скелдон,
@MattSkeldon, понятия не имею, что означает это сообщение. В ванильном PostgreSQL вы можете удалить любую базу данных, кроме template0 и template1. Может быть, вы используете какую-то несвободную / коммерческую версию? Может быть, это проблема клиента, а не сервера? Ты пробовал psql?
filiprem
К сожалению, я пришел из SQL, используя PGSQL из-за некоммерческого / свободного статуса.
Мэтт Скелдон
Это не работает для меня, где есть продолжительные сессии зомби. pg_terminate_backend () не убивает эти сессии, поэтому я все еще немного застрял в том, что делать: я - Postgres su, но у меня нет доступа к серверу, на котором он работает.
Александр
6

Там является способ сделать это с помощью утилиты оболочки dropdbи pg_ctl(или pg_ctlclusterв Debian и дериватов). Но метод @ filiprem лучше по нескольким причинам:

  • Это только отключает пользователей от рассматриваемой базы данных.
  • Не нужно перезагружать весь кластер.
  • Это предотвращает немедленное переподключение, возможно, портит dropdbкоманду.

Я цитирую man pg_ctlcluster:

С --forceопцией используется «быстрый» режим, который откатывает все активные транзакции, немедленно отключает клиентов и, таким образом, корректно завершает работу. Если это не сработает, попытка выключения будет предпринята снова в «немедленном» режиме, который может привести кластер в несогласованное состояние и, таким образом, привести к запуску восстановления при следующем запуске. Если это по-прежнему не помогает, процесс postmaster убивается. Выход с 0 при успешном завершении, с 2, если сервер не работает, и с 1 при других условиях сбоя. Этот режим следует использовать только тогда, когда машина собирается выключиться.

pg_ctlcluster 9.1 main restart --force

или же

pg_ctl restart -D datadir -m fast

или же

pg_ctl restart -D datadir -m immediate

сразу же после:

dropdb mydb

Возможно в сценарии для немедленной преемственности.

Эрвин Брандштеттер
источник
4
Мало того, что это не идеально, так как он запускает полный экземпляр postgres, но он не гарантированно работает. Клиент может установить соединение между моментом перезапуска сервера и повторной попытки запуска dropdb. Ответ @filiprem, приведенный выше, отключает все подключения к базе данных перед отключением и будет поддерживать другие базы данных.
Джим Митченер
6

Используя ответ @ filiprem в моем случае и упростив его:

-- Connecting to the current user localhost's postgres instance
psql

-- Making sure the database exists
SELECT * from pg_database where datname = 'my_database_name'

-- Disallow new connections
UPDATE pg_database SET datallowconn = 'false' WHERE datname = 'my_database_name';
ALTER DATABASE my_database_name CONNECTION LIMIT 1;

-- Terminate existing connections
SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'my_database_name';

-- Drop database
DROP DATABASE my_database_name
Дориан
источник
0

Если вы работаете с чем-то вроде RDS, где соединения без выбранной базы данных помещают вас в БД, которую вы просили создать по умолчанию, вы можете сделать этот вариант, чтобы обойти себя как последнее открытое соединение.

 DROP DATABASE IF EXISTS temporary_db_that_shouldnt_exist; 

 CREATE DATABASE temporary_db_that_shouldnt_exist with OWNER your_user; 

 \connect temporary_db_that_shouldnt_exist 
 SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'the_db_you_want_removed'; 


 DROP DATABASE IF EXISTS the_db_you_want_removed; 
 -- 
 -- Name: the_db_you_want_removed; Type: DATABASE; Schema: -; Owner: your_user 
 -- 

 CREATE DATABASE savings_champion WITH TEMPLATE = template0 ENCODING = 'UTF8' LC_COLLATE = 'en_US.UTF-8' LC_CTYPE = 'en_US.UTF-8'; 


 ALTER DATABASE the_db_you_want_removed OWNER TO your_user; 

 \connect the_db_you_want_removed 

 DROP DATABASE IF EXISTS temporary_db_that_shouldnt_exist;
Jharwood
источник