Skema sementara per koneksi?

8

Saya mencoba untuk memigrasi tes unit saya dari H2 ke Postgresql.

Saat ini, H2 memberi saya skema dalam memori sehingga setiap koneksi memetakan ke skema unik, membuat tabel, menjalankan tes, dan menjatuhkan skema. Pembuatan dan penghancuran skema ditangani secara otomatis oleh H2.

Tes unit berjalan bersamaan.

Apa cara terbaik untuk melakukan ini di Postgresql? Secara khusus,

  1. Bagaimana cara mendapatkan skema unik per koneksi?
    • Haruskah kerangka pengujian menghasilkan nama unik atau apakah ada mekanisme bawaan untuk melakukan ini?
  2. Bagaimana cara saya memastikan bahwa skema dibatalkan ketika koneksi terputus?
    • Saya tidak ingin berakhir dengan skema menggantung ketika tes unit terbunuh.
  3. Pendekatan apa yang akan menghasilkan kinerja tertinggi?
    • Saya perlu membuat / menjatuhkan puluhan skema per detik.

UPDATE : Saya menemukan jawaban terkait di sini tetapi gagal untuk menjatuhkan skema jika proses menjalankan tes unit terbunuh.

Gili
sumber

Jawaban:

13

pg_temp adalah alias untuk skema sementara sesi saat ini.

Jika Anda melakukan SET search_path TO pg_tempsebelum menjalankan tes, semuanya harus berfungsi (selama tidak ada yang merujuk skema secara eksplisit).

Jika Anda tidak ingin mengubah skrip sama sekali, maka setel search_pathpada pengguna yang tes masuk sebagai:

> ALTER ROLE testuser SET search_path = pg_temp;

Maka semua yang dibuat pengguna akan berada di pg_temp kecuali ditentukan secara eksplisit.

Ini adalah contoh dari psql, yang menunjukkan skema aktual (untuk koneksi ini) yang diputuskan oleh alias:

> 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)

Dan, seperti yang Anda harapkan, skema itu berbeda untuk setiap koneksi bersamaan, dan hilang setelah koneksi ditutup.

Perhatikan bahwa ini juga berfungsi untuk fungsi, meskipun Anda harus secara eksplisit merujuk skema pg_temp saat memanggil mereka.

hbn
sumber
Tetapi pg_tempapakah satu skema itu benar? Jadi ketika saya menjalankan tes unit bersamaan, tidakkah mereka akan saling menghancurkan tabel / data masing-masing?
Gili
1
Tidak. Ini alias untuk skema sementara sesi saat ini. Saya akan memperbarui jawabannya dengan sebuah contoh.
hbn
Ingatlah jika Anda hanya menutup dan membuka koneksi, Anda mungkin berakhir dengan skema sementara yang sama, tetapi itu akan dikosongkan. Buka 2 secara bersamaan untuk melihat alokasi yang berbeda. Anda tidak dapat melihat skema sementara sesi lain kecuali Anda superuser.
hbn
Tentu saya melihat komentar dari Anda bertanya tentang kapan harus mengatur ini. Pokoknya - itu diatur per sesi jika Anda hanya melakukan SET search_path; gunakan SET LOCAL search_pathuntuk mengatur per subtransaksi, atau jika Anda ingin, Anda dapat mengatur di tingkat pengguna dengan ALTER USER mytestuser SET search_path = 'pg_temp', atau di tingkat basis data denganALTER DATABASE mytestdb SET search_path = 'pg_temp'
hbn
Karena penasaran, apakah ada cara untuk membuat ini berfungsi untuk fungsi tanpa referensi skema eksplisit? Atau apakah ini mustahil untuk pg_tempskema ini?
Gili
3

Anda bisa mendapatkan nama skema sementara saat ini (setelah membuat tabel temp pertama) seperti diletakkan di tautan yang Anda tambahkan:

SELECT nspname
FROM   pg_namespace
WHERE  oid = pg_my_temp_schema();

Tetapi rencana Anda saat ini masih tidak masuk akal. Untuk membuat tabel dalam skema sementara saat ini, cukup buat tabel sementara. Itu saja. Secara default, search_pathini didefinisikan sehingga tabel sementara terlihat pertama. Satu tidak pernah perlu skema-kualifikasi tabel temp. Anda seharusnya tidak perlu menangani skema sementara saat ini secara langsung dengan cara apa pun - itu adalah detail implementasi.

Erwin Brandstetter
sumber
Setuju itu adalah peretasan, tetapi mungkin jauh lebih mudah daripada kode pembuatan parameter untuk memungkinkan tabel sementara dibuat.
hbn
Poin bagus, kecuali seperti @hbn disebutkan saya ingin unit test dan kode produksi untuk menjalankan skrip SQL yang sama. Yang pertama harus berjalan melawan skema sementara sementara yang kedua seharusnya tidak.
Gili
@ Hbn, karena penasaran seperti apa bentuk kode pembuatan parameter? Saya menggunakan flywaydb.org dan hanya menjalankan file SQL biasa (tidak ada variabel). Saya mungkin tidak ingin menyusuri jalan ini. Saya hanya ingin tahu apa yang terlibat.
Gili
Saya tidak pernah menggunakan flywaydb. Pada tingkat yang sangat dasar, Anda bisa menggunakan beberapa bahasa templating teks (misalnya Jinja2 dengan Python) untuk memproses ulang skrip kreasi Anda, secara opsional menambahkan "sementara" ketika Anda membuat tabel. Jika Anda secara eksplisit membuat fungsi, retasan skema get-temporer mungkin tidak dapat dihindari (sejauh yang saya tahu), Anda tidak dapat secara langsung membuat fungsi sementara.
hbn
@ Hbn,: If you're explicitly sequences ...Saya pikir komentar terakhir Anda berisi salah ketik. Apa yang ingin Anda katakan antara explicitlydan sequences?
Gili
1

Apakah tes Anda melibatkan transaksi? DDL bersifat transaksional dalam PostgreSQL, jadi jika Anda membuat skema dan tabel Anda, kemudian jalankan tes Anda, semuanya dalam satu transaksi yang kemudian dibatalkan, skema tersebut tidak pernah benar-benar dilakukan dan terlihat oleh sesi lain.

Anda masih perlu menggunakan nama yang mungkin unik untuk skema Anda (mungkin menyertakan nama host dan PID), karena CREATE SCHEMAakan segera gagal jika skema yang dinamai identik sudah ada, dan akan diblokir jika sesi lain telah membuat skema yang bernama identik di transaksi yang tidak terikat.

Alternatifnya mungkin hanya menggunakan tabel sementara, jika Anda dapat memodifikasi skrip pembuatan basis data Anda untuk melakukan itu.

hbn
sumber
Trik yang bagus, tetapi tidak akan berhasil dalam kasus saya karena satu tes beroperasi di beberapa transaksi. Setiap metode pengujian adalah klien web yang melakukan beberapa transaksi di sisi server. Misalnya, ia membuat, menanyakan, dan menghapus pengguna. Setiap panggilan adalah permintaan HTTP yang terpisah, dan berjalan dalam transaksinya sendiri.
Gili
Cukup adil, pendekatan saya sangat terbatas.
hbn
@ Geili: Perhatikan bahwa teknik tidak pernah melakukan CREATE SCHEMAini adalah satu-satunya yang dapat menjamin mereka menghilang ketika tes unit terbunuh.
Daniel Vérité
0

Saya baru saja mendapat ide.

Postgresql menjamin bahwa suatu sesi tidak dapat melihat tabel sementara orang lain. Saya menduga ini berarti bahwa ketika Anda membuat tabel sementara, itu membuat skema sementara. Jadi mungkin saya bisa melakukan hal berikut:

  1. Buat tabel sementara (dummy) dan lihat skemanya.
  2. Gunakan skema ini untuk tes (buat tabel, jalankan tes).
  3. Ketika koneksi ditutup, Postgresql akan menjatuhkan skema.

Saya tidak suka mengandalkan detail implementasi, tetapi dalam hal ini sepertinya cukup aman.

Gili
sumber