PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Permintaan Postgresql 9.4 semakin lambat saat bergabung dengan TSTZRANGE dengan &&

Batasan pengecualian

Saya sarankan Anda menggunakan batasan pengecualian, yang jauh lebih sederhana, lebih aman, dan lebih cepat:

Anda perlu menginstal modul tambahan btree_gist pertama. Lihat instruksi dan penjelasan dalam jawaban terkait ini:

Dan Anda harus menyertakan "ParentID" dalam tabel "Bar" berlebihan, yang akan menjadi harga kecil yang harus dibayar. Definisi tabel dapat terlihat seperti ini:

CREATE TABLE "Foo" (
   "FooID"    serial PRIMARY KEY
   "ParentID" int4 NOT NULL REFERENCES "Parent"
   "Details1" varchar
   CONSTRAINT foo_parent_foo_uni UNIQUE ("ParentID", "FooID")  -- required for FK
);

CREATE TABLE "Bar" (
   "ParentID"  int4 NOT NULL,
   "FooID"     int4 NOT NULL REFERENCES "Foo" ("FooID"),
   "Timerange" tstzrange NOT NULL,
   "Detail1"   varchar,
   "Detail2"   varchar,
   CONSTRAINT "Bar_pkey" PRIMARY KEY ("FooID", "Timerange"),
   CONSTRAINT bar_foo_fk
      FOREIGN KEY ("ParentID", "FooID") REFERENCES "Foo" ("ParentID", "FooID"),
   CONSTRAINT bar_parent_timerange_excl
      EXCLUDE USING gist ("ParentID" WITH =, "Timerange" WITH &&)
);

Saya juga mengubah tipe data untuk "Bar"."FooID" dari int8 ke int4 . Ini merujuk pada "Foo"."FooID" , yang merupakan serial , yaitu int4 . Gunakan jenis pencocokan int4 (atau cukup integer ) karena beberapa alasan, salah satunya adalah kinerja.

Anda tidak memerlukan pemicu lagi (setidaknya tidak untuk tugas ini), dan Anda tidak membuat indeks "Bar_FooID_Timerange_idx" lagi, karena dibuat secara implisit oleh batasan pengecualian.

Indeks btree pada ("ParentID", "FooID") kemungkinan besar akan berguna, meskipun:

CREATE INDEX bar_parentid_fooid_idx ON "Bar" ("ParentID", "FooID");

Terkait:

Saya memilih UNIQUE ("ParentID", "FooID") dan bukan sebaliknya karena suatu alasan, karena ada indeks lain dengan "FooID" di depan di salah satu tabel:

Selain:Saya tidak pernah menggunakan CaMeL yang dikutip ganda -pengidentifikasi kasus di Postgres. Saya hanya melakukannya di sini untuk mematuhi tata letak Anda.

Hindari kolom yang berlebihan

Jika Anda tidak dapat atau tidak akan menyertakan "Bar"."ParentID" berlebihan, ada lagi nakal cara - dengan syarat "Foo"."ParentID" tidak pernah diperbarui . Pastikan itu, dengan pemicu misalnya.

Anda dapat memalsukan IMMUTABLE fungsi:

CREATE OR REPLACE FUNCTION f_parent_of_foo(int)
  RETURNS int AS
'SELECT "ParentID" FROM public."Foo" WHERE "FooID" = $1'
  LANGUAGE sql IMMUTABLE;

Saya memenuhi syarat skema nama tabel untuk memastikan, dengan asumsi public . Sesuaikan dengan skema Anda.

Selengkapnya:

Kemudian gunakan dalam batasan pengecualian:

   CONSTRAINT bar_parent_timerange_excl
      EXCLUDE USING gist (f_parent_of_foo("FooID") WITH =, "Timerange" WITH &&)

Saat menyimpan satu int4 yang berlebihan kolom, kendala akan lebih mahal untuk diverifikasi dan seluruh solusi bergantung pada lebih banyak prasyarat.

Menangani konflik

Anda dapat membungkus INSERT dan UPDATE ke dalam fungsi plpgsql dan menjebak kemungkinan pengecualian dari batasan pengecualian (23P01 exclusion_violation ) untuk mengatasinya.

INSERT ...

EXCEPTION
    WHEN exclusion_violation
    THEN  -- handle conflict

Contoh kode lengkap:

Menangani konflik di Postgres 9.5

Di Postgres 9.5 anda dapat menangani INSERT langsung dengan implementasi "UPSERT" yang baru. Dokumentasi:

Namun:

Tapi Anda masih bisa menggunakan ON CONFLICT DO NOTHING , sehingga menghindari kemungkinan exclusion_violation pengecualian. Cukup periksa apakah ada baris yang benar-benar diperbarui, mana yang lebih murah:

INSERT ... 
ON CONFLICT ON CONSTRAINT bar_parent_timerange_excl DO NOTHING;

IF NOT FOUND THEN
   -- handle conflict
END IF;

Contoh ini membatasi pemeriksaan ke batasan pengecualian yang diberikan. (Saya menyebutkan batasan secara eksplisit untuk tujuan ini dalam definisi tabel di atas.) Pengecualian lain yang mungkin tidak tertangkap.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Penyortiran angka manusiawi atau alami dari string kata-dan-angka campuran

  2. Perintah COPY bawaan Postgresql dengan Parameterized Query

  3. Pengaturan Replikasi Slony-I Sederhana.

  4. Laravel 5 memperbarui batas baris tunggal tidak berfungsi

  5. bagaimana cara mengatur perintah psql di cygwin?