Postgresql-DBへの自動接続が原因でデータベースを削除できません


162

私がデータベースを削除しようとするたびに、私は次のようになります:

ERROR:  database "pilot" is being accessed by other users
DETAIL:  There is 1 other session using the database.

私が使うとき:

SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'TARGET_DB';

そのDBからの接続を終了しましたが、その後データベースをドロップしようとすると、誰かがそのデータベースに自動的に接続してこのエラーが発生します。何ができるでしょうか?私を除いて、誰もこのデータベースを使用していません。

回答:


196

今後の接続を防ぐことができます:

REVOKE CONNECT ON DATABASE thedb FROM public;

(そしておそらく他のユーザー/ロール。を参照\l+してくださいpsql

その後、自分以外のこのdbへのすべての接続を終了できます。

SELECT pid, pg_terminate_backend(pid) 
FROM pg_stat_activity 
WHERE datname = current_database() AND pid <> pg_backend_pid();

古いバージョンでpidは呼ばれていたprocpidので、それに対処する必要があります。

CONNECT権利を取り消したので、自動接続しようとしていたものは何もできなくなります。

これで、DBをドロップできるようになります。

これは、通常の操作にスーパーユーザー接続を使用している場合は機能しませんが、その場合はまずその問題を修正する必要があります。


データベースの削除が完了したら、データベースを再度作成する場合、以下のコマンドを実行してアクセスを復元できます

GRANT CONNECT ON DATABASE thedb TO public;

19
後で同じ名前の別のデータベースをインポートする場合、公衆背面に接続機能を付与しますGRANT CONNECT ON DATABASE thedb TO public;
ミハイルVasin

156

私がデータベースを削除しようとするたびに、私は次のようになります:

ERROR:  database "pilot" is being accessed by other users
DETAIL:  There is 1 other session using the database.

まず、取り消す必要があります

REVOKE CONNECT ON DATABASE TARGET_DB FROM public;

次に使用します:

SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'TARGET_DB';

きっと動作します。


5
これでうまくいきました。ありがとう
rpivovar

1
スポット!ありがとうございました!🎉
slajma

1
完璧に働いた。ありがとうございました。
Mustafa Magdi

34

この問題の解決策を見つけたターミナルでこのコマンドを実行しよう

ps -ef | grep postgres

このコマンドによるプロセスの強制終了

sudo kill -9 PID

いいえ、ハードコードが多すぎます。アクセスされている他のデータベースがあるためにpgプロセスをキルできない場合はどうでしょうか。
Vladimir Stazhilov

2
@VladimirStazhilovデータベース名とそのデータベースのpidが表示されます。特定のpid killを選択できるのは、その特定のデータベースだけです。
Dinesh Pallapa 2018年

29

接続が何であるか、どこから来ているのかを確認するだけです。あなたはこれですべてを見ることができます:

select * from pg_stat_activity where datname = 'TARGET_DB';

おそらくそれはあなたのつながりですか?


4
sudo kill -9結果を確認した後、ターミナルでPID
Dan Rey Oquindo

25

これは、別のユーザーがデータベースにアクセスしていることを意味します。PostgreSQLを再起動するだけです。このコマンドはトリックを行います

root@kalilinux:~#sudo service postgresql restart

次に、データベースを削除してみます。

postgres=# drop database test_database;

これでうまくいきます。


11

UIを使用したpgAdmin 4ソリューション

最初に、ダッシュボードのショーアクティビティを有効にします。

File > Preferences > Dashboards > Display > Show Activity > true

ここで、dbを使用してすべてのプロセスを無効にします。

  1. DB名をクリックします
  2. [ダッシュボード]> [セッション]をクリックします
  3. 更新アイコンをクリックします
  4. 各プロセスの横にある削除(x)アイコンをクリックして、プロセスを終了します。

これでデータベースを削除できるはずです。


これはうまく機能します-Visual C ++ビルド1914、64ビット(Windows)でコンパイルされたPgAdmin 4.5およびPostgreSQL 11.2でテストしました。
vab2048

2
これは私が思う最高の解決策です。これは本当にうまくいきます!
Lahiru


8

解決策:
1. Pgサーバーをシャットダウンします 2.すべてのアクティブな接続を切断します 3. Pgサーバーを再起動します 4.コマンドを試します
ここに画像の説明を入力してください




これは、MacのPostgress.appでも機能しました。その場合、サーバーを停止/起動します
JuanJoséRamírez


3

私の場合、AWS Redshift(Postgresベース)を使用しています。そして、DBへの他の接続はないようですが、これと同じエラーが発生しています。

ERROR:  database "XYZ" is being accessed by other users

私の場合、データベースクラスターはまだデータベースで何らかの処理を行っているようです。他の外部/ユーザー接続がない間、データベースはまだ内部で使用されています。次のコマンドを実行してこれを見つけました:

SELECT * FROM stv_sessions;

したがって、私のハックは、コードにループを記述し、データベース名が含まれる行を探すことでした。(もちろん、ループは無限ではなく、眠いループなどです)

SELECT * FROM stv_sessions where db_name = 'XYZ';

行が見つかった場合は、各PIDを1つずつ削除します。

SELECT pg_terminate_backend(PUT_PID_HERE);

行が見つからない場合は、データベースの削除に進みます

DROP DATABASE XYZ;

注:私の場合、Javaユニット/システムテストを作成しています。これは、量産コードでは受け入れられません。


Javaでの完全なハックは次のとおりです(テスト/ユーティリティクラスは無視してください)。

  int i = 0;
  while (i < 10) {
    try {
      i++;
      logStandardOut("First try to delete session PIDs, before dropping the DB");
      String getSessionPIDs = String.format("SELECT stv_sessions.process, stv_sessions.* FROM stv_sessions where db_name = '%s'", dbNameToReset);
      ResultSet resultSet = databaseConnection.execQuery(getSessionPIDs);
      while (resultSet.next()) {
        int sessionPID = resultSet.getInt(1);
        logStandardOut("killPID: %s", sessionPID);
        String killSessionPID = String.format("select pg_terminate_backend(%s)", sessionPID);
        try {
          databaseConnection.execQuery(killSessionPID);
        } catch (DatabaseException dbEx) {
          //This is most commonly when a session PID is transient, where it ended between my query and kill lines
          logStandardOut("Ignore it, you did your best: %s, %s", dbEx.getMessage(), dbEx.getCause());
        }
      }

      //Drop the DB now
      String dropDbSQL = String.format("DROP DATABASE %s", dbNameToReset);
      logStandardOut(dropDbSQL);
      databaseConnection.execStatement(dropDbSQL);
      break;
    } catch (MissingDatabaseException ex) {
      //ignore, if the DB was not there (to be dropped)
      logStandardOut(ex.getMessage());
      break;
    } catch (Exception ex) {
      logStandardOut("Something went wrong, sleeping for a bit: %s, %s", ex.getMessage(), ex.getCause());
      sleepMilliSec(1000);
    }
  }

2

私の意見では、背景でいくつかのアイドルクエリが実行されています。

  1. 最初に実行中のクエリを表示してみてください
SELECT pid, age(clock_timestamp(), query_start), usename, query 
FROM pg_stat_activity 
WHERE query != '<IDLE>' AND query NOT ILIKE '%pg_stat_activity%' 
ORDER BY query_start desc;
  1. kill idle query(問題のデータベースを参照しているかどうかを確認します。または、選択した結果のpidを使用して、それらすべてを強制終了するか、特定のものを強制終了できます)

SELECT pg_terminate_backend(procpid);

注:選択クエリを強制終了しても、悪影響はありません。


2

REVOKE CONNECTdb所有者またはスーパーユーザーからの接続を妨げません。したがって、誰にもdbを接続させたくない場合は、followコマンドが役立つ場合があります。

alter database pilot allow_connections = off;

次に使用します:

SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = 'pilot';

1
ありがとう... REVOKE CONNECTは私のシナリオでは不十分でした。
volpato

1

他の場合にも2つの回答が役立つことがわかりましたが、今日、問題を解決する最も簡単な方法は、PyCharmがセッションを開いたままにしている可能性があることを認識することでした。PyCharmをクリックStopすると、それが役立つ場合があります。ブラウザーでpgAdmin4を開いた状態で、そうしたところ、すぐにデータベースセッションの統計が0に下がり、その時点でデータベースをドロップすることができました。


「PyCharmはセッションを開いたままにしている可能性があります」?どうやって?私はPyCharmのターミナル(peeweeを備えたフロントエンドPython、バックエンドPostgres)で単体テストを実行します。つまり、[停止]ボタンがグレー表示され、それでもこれらのエラーを保持します...
Laryx Decidua

@LaryxDecidua私の場合、私はPyCharmでdbを使用するサービスのインスタンスを実行している必要があると思います。PyCharmを終了すると、インスタンスの数は0になり、dbを削除できるようになりますか?その場合は、まだ接続されているもの(データベースエクスプローラー、SQLクエリなど)が存在する必要があります。
hlongmore

1

macOSでは、次のコマンドを使用して、コンソールからpostgresqlデータベースを再起動してください。

brew services restart postgresql

-1

端末で次のコマンドを試してください:

ps -ef | grep postgres

次のように表示されます:

501 1445 3645 0 12:05 AM 0:00.03 postgres:sasha dbname [local] idle

3番目の番号(3645)はPIDです。

これを削除できます

sudo kill -9 3645

その後、PostgreSQL接続を開始します。

手動で開始:

pg_ctl -D /usr/local/var/postgres start
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.