2011-10-24 16 views
2

私は、既存のPostgreSQL 9.1データベースの構造を読み、それを "should be"状態と比較してそれに応じてデータベースを更新するアプリケーションを持っています。それはほとんどの場合、大丈夫です。しかし、現在デッドロックされている現在のデータベース構造を読むときに、私はいくつかのインスタンスを持っていました。責任のクエリは、既存の外部キーを読み取りますpgAdminで、サーバのステータスを表示なぜこのクエリはデッドロックですか?

SELECT tc.table_schema, tc.table_name, tc.constraint_name, kcu.column_name, 
     ccu.table_schema, ccu.table_name, ccu.column_name 
FROM information_schema.table_constraints AS tc 
JOIN information_schema.key_column_usage AS kcu 
    ON tc.constraint_name = kcu.constraint_name 
JOIN information_schema.constraint_column_usage AS ccu 
    ON ccu.constraint_name = tc.constraint_name 
WHERE constraint_type = 'FOREIGN KEY' 

が、これは、サーバー上で実行している唯一のアクティブクエリ/トランザクションであることを示しています。それでも、クエリは返されません。

エラーは再現性があります。エラーを生成するデータベースを見つけると、毎回エラーが発生します。しかし、すべてのデータベースでエラーが発生するわけではありません。これは不思議なバグの1つで、これ以外に何を試していくのか、これを回避する方法については、オプションやアイデアが不足しています。だから、どんな入力やアイデアも高く評価されています!

PS:私の同僚は、PostgreSQL 8.4を使用して同じエラーが発生したとちょうど報告しました。

+0

私のマシン上のテストデータベースでは約7秒、約8秒かかります。 EXPLAINを実行してクエリの実行方法を確認し、すべてのコストがどこにあるかを確認してください。 –

+0

@フランク、ありがとう! EXPLAINを考えていなかったので、次回エラーが表示されるように試みます。しかし、現時点では、これはランタイムではなく、明らかにデッドロックです。クエリは私のDBで1.5秒かかる...それが返された場合。 – Robin

答えて

1

非常に遅いも検索しました。この問題の根本は、information_schemaの "tables"は、実際にはSQL標準に従ってカタログを提供するための複雑なビューであるということです。この特定のケースでは、複数の列に外部キーを構築できるため、問題はさらに複雑になります。あなたのクエリは、望ましくない副作用であるかもしれない疑いがある場合は、重複行を返します。

これは、下のクエリでunnestARRAYというサブクエリ構成の理由もあります。

この代替クエリを検討してください。同じ情報が得られます。は重複行なしで、100倍高速のです。また、私はデッドロックを起こすことなく保証するつもりです。

もちろん、このクエリはPostgreSQLでのみ機能し、他のRDBMSでは移植できません。私はspecial casting operation table_oid::regclassを使用

SELECT c.conrelid::regclass AS table_name 
     ,c.conname AS fk_name 
     ,ARRAY(SELECT a.attname 
      FROM unnest(c.conkey) x 
      JOIN pg_attribute a 
      ON  a.attrelid = c.conrelid AND a.attnum = x) AS fk_columns 
     ,c.confrelid::regclass AS ref_table 
     ,ARRAY(SELECT a.attname 
      FROM unnest(c.confkey) x 
      JOIN pg_attribute a 
      ON  a.attrelid = c.confrelid AND a.attnum = x) AS ref_columns 
FROM pg_catalog.pg_constraint c 
WHERE c.contype = 'f'; 
-- ORDER BY c.conrelid::regclass::text,2 

。現在アクティブなsearch_pathのテーブル名が表示されます。それはあなたが望むものかもしれません。このクエリすべてのテーブル名に絶対パス(スキーマ)を含むようにすることができますset the search_path like thisについて:

SET search_path = pg_catalog; 
SELECT ... 

おそらく、残りの部分を知っているが、私は一般の人々のためにそれを含めます。
あなたはこのセッションで継続し、その後、戻ってあなたのデフォルトのsearch_pathをしたい場合:カスタムsearch_pathを使用する必要がある場合には

RESET search_path; 

を、あなたは再びそれを設定する必要があります。

+0

ありがとう!それは私が期待していたよりもはるかに多くでしたクエリは本当にはるかに高速です。そして今のところ、私はそれで私のデッドロックを再現することができませんでした。再度、感謝します! – Robin

関連する問題