Buat indeks jika tidak ada

60

Saya sedang mengerjakan fungsi yang memungkinkan saya untuk menambah indeks jika tidak ada. Saya mengalami masalah yang tidak bisa saya bandingkan dengan daftar indeks. Adakah pikiran?

Ini adalah masalah yang mirip dengan pembuatan kolom yang diselesaikan dengan kode ini:
https://stackoverflow.com/a/12603892/368511

GuidoS
sumber
Anda dapat mencoba: SELECT * dari pg_indexes di mana schemaname = '[schemaname]' dan indexname = '[indexname]'. Ganti [schemaname] dan [indexname] dengan nilai yang tepat. Ref: postgresql.org/docs/9.1/static/view-pg-indexes.html
jbarrameda

Jawaban:

102

Nama indeks di PostgreSQL

  • Nama indeks unik di seluruh skema basis data tunggal.
  • Nama indeks tidak boleh sama dengan indeks lainnya, tabel (asing), tampilan (terwujud), urutan, atau tipe komposit yang ditentukan pengguna dalam skema yang sama.
  • Dua tabel dalam skema yang sama tidak dapat memiliki indeks dengan nama yang sama. (Mengikuti secara logis.)

Jika Anda tidak peduli dengan nama indeks, mintalah nama Postgres secara otomatis:

CREATE INDEX ON tbl1 (col1);

hampir sama dengan:

CREATE INDEX tbl1_col1_idx ON tbl1 USING btree (col1);

Kecuali bahwa Postgres akan menghindari tabrakan penamaan dan secara otomatis memilih nama gratis berikutnya:

tbl1_col1_idx 
tbl1_col1_idx2
tbl1_col1_idx3
...

Cobalah. Tapi, jelas, Anda tidak ingin membuat beberapa indeks berlebihan. Jadi bukan ide yang bagus untuk secara buta membuat yang baru.

Uji keberadaan

Postgres 9.3 atau lebih tua

Cara yang sangat sederhana untuk menguji adalah dengan memasukkan nama yang memenuhi syarat skema ke regclass:

SELECT 'myschema.myname'::regclass;

Jika ada pengecualian, nama itu gratis.
Atau, untuk menguji hal yang sama tanpa melemparkan pengecualian, digunakan dalam DOpernyataan:

DO
$$
BEGIN
   IF NOT EXISTS (
      SELECT
      FROM   pg_class c
      JOIN   pg_namespace n ON n.oid = c.relnamespace
      WHERE  c.relname = 'mytable_mycolumn_idx'
      AND    n.nspname = 'myschema'
   ) THEN

        CREATE INDEX mytable_mycolumn_idx ON myschema.mytable (mycolumn);
    END IF;
END
$$;

Ini tidak berfungsi CREATE INDEX CONCURRENTLY, karena varian itu tidak dapat dibungkus dengan transaksi luar. Lihat komentar oleh @Gregory di bawah ini.

The DOpernyataan diperkenalkan dengan Postgres 9.0. Di versi sebelumnya Anda harus membuat fungsi untuk melakukan hal yang sama.
Detail tentang pg_classdi manual .
Dasar-dasar tentang indeks dalam manual .

Postgres 9.4

Anda dapat menggunakan fungsi baru to_regclass()untuk memeriksa tanpa melemparkan pengecualian:

DO
$$
BEGIN
   IF to_regclass('myschema.mytable_mycolumn_idx') IS NULL THEN
      CREATE INDEX mytable_mycolumn_idx ON myschema.mytable (mycolumn);
   END IF;

END
$$;

Mengembalikan NULL jika indeks (atau objek lain) dari nama itu tidak ada. Lihat:

Postgres 9.5

Sekarang tersedia:

CREATE INDEX IF NOT EXISTS ...

Itu juga berhasil CREATE INDEX CONCURRENTLY IF NOT EXISTS.

Namun, manual ini memperingatkan :

Perhatikan bahwa tidak ada jaminan bahwa indeks yang ada adalah sesuatu seperti yang akan dibuat.

Ini pemeriksaan sederhana untuk nama objek. Berlaku untuk semua varian di sini.

Erwin Brandstetter
sumber
7
Sementara menjadi jawaban yang bagus, harap perhatikan bahwa Anda tidak dapat menambahkan indeks CONCURRENTLYdengan cara ini. Anda akan mendapatkannya ERROR: CREATE INDEX CONCURRENTLY cannot be executed from a function or multi-command string.
gregoltsov