Принудительное падение db, в то время как другие могут быть связаны

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

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

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

73 голоса | спросил Alex 30 Jpm1000000pmMon, 30 Jan 2012 15:28:09 +040012 2012, 15:28:09

4 ответа


110

Начиная с версии 9.5 вы не можете удалить базу данных Postgres, пока клиенты подключены к ней, используя только dropdb - это простая оболочка вокруг DROP DATABASE серверный запрос.

Достаточно надежное обходное решение:

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

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 .

    Для Postgres <9.2:

    SELECT pg_terminate_backend(procpid)
    FROM pg_stat_activity
    WHERE datname = 'mydb';
    

    Для версий Postgres> = 9.2 изменить procpid на pid:

    SELECT pg_terminate_backend(pid)
    FROM pg_stat_activity
    WHERE datname = 'mydb';
    
  3. Отбросьте его.

    DROP DATABASE mydb;
    

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


ответил filiprem 30 Jpm1000000pmMon, 30 Jan 2012 15:51:29 +040012 2012, 15:51:29
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

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

ответил Erwin Brandstetter 30 Jpm1000000pmMon, 30 Jan 2012 20:15:33 +040012 2012, 20:15:33
1

Используя ответ @ 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
ответил Dorian 9 FebruaryEurope/MoscowbThu, 09 Feb 2017 02:02:23 +0300000000amThu, 09 Feb 2017 02:02:23 +030017 2017, 02:02:23
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 29 MarpmThu, 29 Mar 2018 15:25:46 +03002018-03-29T15:25:46+03:0003 2018, 15:25:46

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132