接続ごとの一時的なスキーマ?


8

単体テストをH2からPostgresqlに移行しようとしています。

現在、H2は、各接続が一意のスキーマにマップされ、テーブルが作成され、テストが実行され、スキーマが削除されるように、メモリ内スキーマを提供します。スキーマの作成と破棄は、H2によって自動的に処理されます。

単体テストは同時に実行されます。

Postgresqlでこれを行う最良の方法は何ですか?具体的には

  1. 接続ごとに一意のスキーマを取得するにはどうすればよいですか?
    • テストフレームワークは一意の名前を生成する必要がありますか、またはこれを行うための組み込みメカニズムはありますか?
  2. 接続がドロップされたときにスキーマが確実にドロップされるようにするにはどうすればよいですか?
    • 単体テストが終了したときにスキーマがぶら下がってしまいたくありません。
  3. どのようなアプローチで最高のパフォーマンスが得られますか?
    • 1秒あたり数十のスキーマを作成/ドロップする必要があります。

更新ここで関連する回答を見つけましたが、単体テストを実行しているプロセスが強制終了された場合にスキーマを削除できません。

回答:


13

pg_temp 現在のセッションの一時スキーマのエイリアスです。

SET search_path TO pg_tempテストを実行する前にa を実行すると、(スキーマを明示的に参照しているものがない限り)すべて正常に機能するはずです。

スクリプトをまったく変更したくない場合はsearch_path、テストがログインするユーザーにを設定します。

> ALTER ROLE testuser SET search_path = pg_temp;

その後、明示的に指定されていない限り、ユーザーが作成するものはすべてpg_tempにあります。

以下psqlは、エイリアスが解決する実際のスキーマ(この接続の場合)を示すの例です。

> SET search_path TO pg_temp;
SET
> create table test();
CREATE TABLE
> \dt test
          List of relations
  Schema   | Name | Type  |  Owner
-----------+------+-------+----------
 pg_temp_4 | test | table | postgres
(1 row)

そして、ご想像のとおり、そのスキーマは同時接続ごとに異なり、接続が閉じられた後に失われます。

これは関数に対しても機能することに注意してください。ただし、関数を呼び出すときにpg_tempスキーマを明示的に参照する必要があります。


しかしpg_temp、単一のスキーマは正しいのでしょうか?それで、同時ユニットテストを実行すると、お互いのテーブル/データが破壊されませんか?
ギリ2014

1
いいえ。現在のセッションの一時スキーマのエイリアスです。例を挙げて回答を更新します。
hbn 2014

接続を閉じて開くだけの場合、同じ一時スキーマになる可能性がありますが、空になります。2を同時に開いて、異なるものが割り当てられていることを確認します。スーパーユーザーでない限り、別のセッションの一時スキーマを表示することはできません。
hbn 2014

確かに、これをいつ設定するかについてあなたからのコメントを見ました。とにかく-あなただけを行う場合は、セッションごとに設定されますSET search_pathSET LOCAL search_pathサブトランザクションごとに設定するために使用するか、必要に応じて、を使用してユーザーレベルでALTER USER mytestuser SET search_path = 'pg_temp'、またはALTER DATABASE mytestdb SET search_path = 'pg_temp'
hbn

好奇心から、明示的なスキーマ参照なしで関数に対してこれを機能させる方法はありますか?または、これはpg_tempスキーマにとって不可能ですか?
ギリ2014

3

あなたはできますが、追加リンクにレイアウトのように(最初の一時テーブルを作成した後)は、現在の一時スキーマの名前を取得します:

SELECT nspname
FROM   pg_namespace
WHERE  oid = pg_my_temp_schema();

しかし、あなたの現在の計画はまだあまり意味がありません。現在の一時スキーマにテーブルを作成するには、一時テーブルを作成するだけです。それで全部です。デフォルトではsearch_path、一時テーブルが最初に表示されるようにが定義されています。一つは、決して、スキーマ修飾する一時テーブルに必要はありません。-あなたはこれまでどのような方法で直接、現在の一時的なスキーマに対処する必要はありません実装の詳細。


これはハックであることに同意しますが、一時テーブルを作成できるように作成コードをパラメーター化するよりもはるかに簡単かもしれません。
hbn 2014

@hbnで言及した場合を除いて、良い点は、ユニットテストと製品コードで同じSQLスクリプトを実行することです。前者は一時スキーマに対して実行する必要がありますが、後者は実行しないでください。
Gili

@hbn、好奇心から、パラメーター化された作成コードはどのようになりますか?私はflywaydb.orgを使用しており、プレーンSQLファイルを実行するだけです(変数はありません)。私はおそらくこの道を下りたくないでしょう。何が関係しているのか気になります。
Gili

flywaydbを使用したことがありません。非常に基本的なレベルでは、テキストテンプレート言語(PythonのJinja2など)を使用して作成スクリプトを前処理し、オプションでテーブルを作成するときに「一時」を追加できます。関数を明示的に作成している場合、(私が知る限り)get-the-temporary-schemaハックはおそらく避けられず、一時的な関数を直接作成することはできません。
2014

@hbn、:If you're explicitly sequences ...最後のコメントにタイプミスがあったと思います。あなたは何の間で言うことを意味したexplicitlyとしますかsequences
Gili

1

テストにはトランザクションが含まれますか?DDLはPostgreSQLでトランザクション対応であるため、スキーマとテーブルを作成してテストを実行すると、すべて1つのトランザクション内でロールバックされ、スキーマが実際にコミットされて他のセッションから見えることはありません。

あなたはまだ、(多分ホスト名とPIDを含む)にスキーマのための、おそらく、固有の名前を使用する必要があるだろうCREATE SCHEMA同じ名前のスキーマがすでに存在する場合は、すぐに失敗し、別のセッションが中に同じ名前のスキーマを作成した場合はブロックします。コミットされていないトランザクション。

別の方法としては、データベース作成スクリプトを変更してそれを実行できる場合は、一時テーブルを使用するだけです。


素敵なトリックですが、私の場合、1つのテストが複数のトランザクションにわたって動作するため、うまくいきません。各テストメソッドは、複数のサーバー側トランザクションを起動するWebクライアントです。たとえば、ユーザーの作成、クエリ、削除を行います。各呼び出しは個別のHTTPリクエストであり、独自のトランザクションで実行されます。
Gili

結局のところ、私のアプローチは非常に限られていました。
2014

@ギリ:コミットしないというこのテクニックはCREATE SCHEMA、ユニットテストが終了したときにそれらを確実に消すことができる唯一のテクニックであることに注意してください。
DanielVérité2014

0

私はちょうどアイデアを得ました。

Postgresqlは、セッションが別の一時テーブルを見ることができないことを保証します。これは、一時テーブルを作成すると一時スキーマが作成されることを意味していると思います。だから私はおそらく次のことをすることができます:

  1. (ダミー)一時テーブルを作成し、そのスキーマを検索します。
  2. このスキーマをテストに使用します(テーブルを作成し、テストを実行します)。
  3. 接続が閉じられると、Postgresqlはスキーマを削除します。

実装の詳細に依存するのは好きではありませんが、この場合はかなり安全に見えます。

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