Tạo chỉ mục nếu nó không tồn tại


60

Tôi đang làm việc trên một chức năng cho phép tôi thêm một chỉ mục nếu nó không tồn tại. Tôi đang gặp vấn đề là tôi không thể lấy danh sách các chỉ mục để so sánh. Có suy nghĩ gì không?

Đây là một vấn đề tương tự như vấn đề tạo cột được giải quyết với mã này:
https://stackoverflow.com/a/12603892/368511


bạn có thể thử: CHỌN * từ pg_indexes trong đó schemaname = '[schemaname]' và indexname = '[indexname]'. Thay thế [schemaname] và [indexname] bằng các giá trị phù hợp. Tham chiếu: postgresql.org/docs/9.1/static/view-pg-indexes.html
jbarrameda

Câu trả lời:


102

Tên chỉ mục trong PostgreSQL

  • Tên chỉ mục là duy nhất trên một lược đồ cơ sở dữ liệu duy nhất.
  • Tên chỉ mục không thể giống như bất kỳ chỉ mục nào khác, bảng (nước ngoài), dạng xem (cụ thể hóa), chuỗi hoặc loại hỗn hợp do người dùng xác định trong cùng một lược đồ.
  • Hai bảng trong cùng một lược đồ không thể có một chỉ mục cùng tên. (Theo sau một cách hợp lý.)

Nếu bạn không quan tâm đến tên của chỉ mục, hãy để Postgres tự động đặt tên cho nó:

CREATE INDEX ON tbl1 (col1);

là (gần như) giống như:

CREATE INDEX tbl1_col1_idx ON tbl1 USING btree (col1);

Ngoại trừ việc Postgres sẽ tránh va chạm đặt tên và tự động chọn tên miễn phí tiếp theo:

tbl1_col1_idx 
tbl1_col1_idx2
tbl1_col1_idx3
...

Hãy thử nó. Nhưng, rõ ràng, bạn sẽ không muốn tạo nhiều chỉ mục dư thừa. Vì vậy, sẽ không phải là một ý tưởng tốt khi chỉ mù quáng tạo ra một cái mới.

Kiểm tra sự tồn tại

Postgres 9.3 trở lên

Một cách rất đơn giản để kiểm tra là chuyển tên đủ điều kiện lược đồ thành regclass:

SELECT 'myschema.myname'::regclass;

Nếu nó ném một ngoại lệ, tên này là miễn phí.
Hoặc, để kiểm tra tương tự mà không đưa ra một ngoại lệ, được sử dụng trong một DOtuyên bố:

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
$$;

Điều này không hoạt động CREATE INDEX CONCURRENTLY, vì biến thể đó không thể được gói trong một giao dịch bên ngoài. Xem bình luận của @Gregory bên dưới.

Các DOtuyên bố đã được giới thiệu với Postgres 9.0. Trong các phiên bản trước, bạn phải tạo một chức năng để làm tương tự.
Chi tiết về pg_classtrong hướng dẫn .
Khái niệm cơ bản về chỉ số trong hướng dẫn .

Hậu 9,4

Bạn có thể sử dụng chức năng mới to_regclass()để kiểm tra mà không cần ném ngoại lệ:

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

END
$$;

Trả về NULL nếu không tồn tại một chỉ mục (hoặc đối tượng khác) của tên đó. Xem:

Hậu 9,5

Hiện tại có sẵn:

CREATE INDEX IF NOT EXISTS ...

Điều đó cũng làm việc cho CREATE INDEX CONCURRENTLY IF NOT EXISTS.

Tuy nhiên, hướng dẫn cảnh báo :

Lưu ý rằng không có gì đảm bảo rằng chỉ mục hiện tại là bất cứ thứ gì giống như chỉ mục sẽ được tạo.

Đó là một kiểm tra đơn giản cho tên đối tượng. Áp dụng cho tất cả các biến thể ở đây.


7
Mặc dù là một câu trả lời tuyệt vời, xin lưu ý rằng bạn không thể thêm chỉ mục CONCURRENTLYtheo cách này. Bạn sẽ nhận được ERROR: CREATE INDEX CONCURRENTLY cannot be executed from a function or multi-command string.
gregoltsov

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.