PostgreSQL thực sự hỗ trợ các chỉ mục GIN trên các cột mảng. Rất tiếc, nó dường như không thể sử dụng được cho NOT ARRAY[...] <@ indexed_col
và GIN
các chỉ mục vẫn không phù hợp với các bảng được cập nhật thường xuyên.
Demo:
CREATE TABLE arrtable (id integer primary key, array_column integer[]);
INSERT INTO arrtable(1, ARRAY[1,2,3,4]);
CREATE INDEX arrtable_arraycolumn_gin_arr_idx
ON arrtable USING GIN(array_column);
-- Use the following *only* for testing whether Pg can use an index
-- Do not use it in production.
SET enable_seqscan = off;
explain (buffers, analyze) select count(id)
from arrtable
where not (ARRAY[1] <@ arrtable.array_column);
Thật không may, điều này cho thấy rằng như đã viết, chúng tôi không thể sử dụng chỉ mục. Nếu bạn không phủ định điều kiện, nó có thể được sử dụng, vì vậy bạn có thể tìm kiếm và đếm các hàng làm chứa phần tử tìm kiếm (bằng cách xóa NOT
).
Bạn có thể sử dụng chỉ mục để đếm các mục nhập làm chứa giá trị đích, sau đó trừ kết quả đó ra khỏi tổng số tất cả các mục nhập. Kể từ count
Việc nhập tất cả các hàng trong bảng khá chậm trong PostgreSQL (9.1 trở lên) và yêu cầu quét tuần tự, điều này thực sự sẽ chậm hơn truy vấn hiện tại của bạn. Có thể trên 9.2, một quá trình quét chỉ chỉ mục có thể được sử dụng để đếm các hàng nếu bạn có chỉ mục b-tree trên id
, trong trường hợp đó, điều này thực sự có thể ổn:
SELECT (
SELECT count(id) FROM arrtable
) - (
SELECT count(id) FROM arrtable
WHERE (ARRAY[1] <@ arrtable.array_column)
);
Nó được đảm bảo hoạt động kém hơn so với phiên bản gốc của bạn cho Pg 9.1 trở xuống, bởi vì ngoài việc quét seqs, bản gốc của bạn còn yêu cầu nó cũng cần quét chỉ mục GIN. Bây giờ tôi đã thử nghiệm điều này trên 9.2 và nó dường như sử dụng một chỉ mục cho số lượng, vì vậy nó đáng để khám phá cho 9.2. Với một số dữ liệu giả ít tầm thường hơn:
drop index arrtable_arraycolumn_gin_arr_idx ;
truncate table arrtable;
insert into arrtable (id, array_column)
select s, ARRAY[1,2,s,s*2,s*3,s/2,s/4] FROM generate_series(1,1000000) s;
CREATE INDEX arrtable_arraycolumn_gin_arr_idx
ON arrtable USING GIN(array_column);
Lưu ý rằng chỉ mục GIN như thế này sẽ làm chậm quá trình cập nhật rất nhiều và khá chậm để tạo ngay từ đầu. Nó không phù hợp với các bảng được cập nhật nhiều - như bảng của bạn.
Tệ hơn nữa, truy vấn sử dụng chỉ mục này cần thời lượng gấp đôi so với truy vấn ban đầu của bạn và tốt nhất là lâu hơn một nửa trên cùng một tập dữ liệu. Điều tồi tệ nhất là đối với các trường hợp chỉ mục không có tính chọn lọc cao như ARRAY[1]
- 4 giây so với 2 giây cho truy vấn ban đầu. Nơi chỉ mục có tính chọn lọc cao (tức là:không có nhiều kết quả phù hợp, như ARRAY[199]
) nó chạy trong khoảng 1,2 giây so với 3 giây của bản gốc. Chỉ mục này đơn giản là không đáng có cho truy vấn này.
Bài học ở đây? Đôi khi, câu trả lời đúng là chỉ quét tuần tự.
Vì điều đó sẽ không hiệu quả đối với tỷ lệ lần truy cập của bạn, hãy duy trì chế độ xem cụ thể hóa với trình kích hoạt như @debenhur đề xuất hoặc cố gắng đảo ngược mảng thành danh sách các tham số mà mục nhập không để bạn có thể sử dụng chỉ mục GiST như @maniek đề xuất.