12

単一のトランザクションで、数百万行のデータをテーブル (ユーザー テーブルへの 2 つの外部キーと、それらのキーに関連付けられたインデックスを含む "フォロー" テーブル) にロードしようとしています。最初の試行で、システム メモリが使い果たされたため、スクリプトがクラッシュしました。

調査の結果、クラッシュの原因は外部キー制約によるものであるという結論に達したため、テーブルが空であること (つまり、プロセスが強制終了されたトランザクションが完了していないこと) を確認し、スクリプトを修正して外部キー制約を削除しました。データを挿入するためのキー制約とインデックス。私の意図は、後で制約とインデックスを再作成することでした。

ただし、テーブルが完全に空であるにもかかわらず、テーブルの最初の外部キー制約を削除する ALTER TABLE DROP CONSTRAINT コマンドには非常に長い時間がかかります (数十分)。

私が考えることができる唯一のことは、スクリプトがクラッシュしたために、テーブルに書き込んだ後にコミットしなかった大量のデータに関連しているということです。しかしもちろん、トランザクションはコミットされていないため、データベースにそのデータの痕跡は見つかりません。

このクエリが遅くなる (またはまったく実行されない可能性があります。この記事の執筆時点ではまだ進行中です) 原因は何ですか?また、それを回避するにはどうすればよいですか?

データベースで開いている他のトランザクションがあります (他の非常に大きなテーブルを移行する数時間のトランザクション) が、それらのトランザクションのどれも次のテーブルに触れていません。

編集: pg ロックは以下のとおりです。

db=#  select relation::regclass, * from pg_locks where not granted;
-[ RECORD 1 ]------+--------------------
relation           | auth_user
locktype           | relation
database           | 53664
relation           | 54195
page               | 
tuple              | 
virtualxid         | 
transactionid      | 
classid            | 
objid              | 
objsubid           | 
virtualtransaction | 5/343
pid                | 17300
mode               | AccessExclusiveLock
granted            | f

上記の pid (17300) は、単に ALTER TABLE クエリそのものです。他のロックはなく、ロックを待っているプロセスもありません。

4

1 に答える 1

16

pg_locks をチェックして、他のトランザクションがテーブルをロックしていないことを確認してください。読み取りロックでも防止できALTER TABLEます。

\x

select 
  pg_class.relname,
  pg_locks.*
from pg_locks 
left outer join pg_class ON (pg_locks.relation = pg_class.oid)
where pg_locks.relation = 'auth_user'::regclass;

元のクエリでフィルタリングすることによりwhere not granted、ブロックしているロックではなく、未解決のロックのみが表示されます。

このロックが許可されていないという事実は、これがロックの問題であることを示しています。別のトランザクションがこのテーブルにロックを保持しているため、処理を続行するために必要な をALTER TABLE取得できません。これは、ある時点でテーブルから ed されたAccessExclusiveLock単なるトランザクションである可能性があります。SELECT

に参加することで見つけることができますpg_stat_activity

select 
  c.relname,
  l.*,
  psa.*
from pg_locks l
inner join pg_stat_activity psa ON (psa.pid = l.pid)
left outer join pg_class c ON (l.relation = c.oid)
where l.relation = 'test'::regclass;

このテーブルでロックを保持または待機しているトランザクション、ロックの内容、それらのトランザクションによって現在実行されているステートメントなどを表示します。

(古いバージョンの場合:pg_stat_activity.pid以前はprocpidでした。古い PostgreSQL を使用している場合は、クエリを適切に変更してください。または、更新してください。)

于 2013-07-12T01:30:26.793 に答える