PostgreSQL thực sự hỗ trợ chỉ mục GIN trên cột mảng. Thật không may, dường như không sử dụng được cho NOT ARRAY[...] <@ indexed_col
và chỉ số GIN
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 khi viết chúng tôi không thể sử dụng các chỉ số. Nếu bạn không phủ nhận đ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 do 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 do chứa giá trị đích, sau đó trừ kết quả đó khỏi tổng số tất cả các mục nhập. Kể từ khi count
ing tất cả các hàng trong một bảng là khá chậm trong PostgreSQL (9.1 trở lên) và yêu cầu quét tuần tự này sẽ thực sự chậm hơn so với truy vấn hiện tại của bạn. Có thể là trên 9,2 một quét chỉ số chỉ có thể được sử dụng để đếm các hàng nếu bạn có một chỉ số b-tree trên id
, trong trường hợp này thực sự có thể OK:
SELECT (
SELECT count(id) FROM arrtable
) - (
SELECT count(id) FROM arrtable
WHERE (ARRAY[1] <@ arrtable.array_column)
);
Nó đảm bảo để thực hiện tồi tệ hơn phiên bản gốc của bạn cho phiên bản 9.1 trở xuống, bởi vì ngoài seqscan, bản gốc của bạn cũng yêu cầu nó cũng cần cần quét chỉ mục GIN. Bây giờ tôi đã thử nghiệm này trên 9.2 và nó xuất hiện để sử dụng một chỉ số cho số lượng, do đó, nó có giá trị khám phá cho 9.2. Với một số dữ liệu giả ít tầm thường:
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 một chỉ số GIN như thế này sẽ làm chậm cập nhật xuống một LOT, và khá chậm chạp trong việc tạo ra ở nơi đầu tiên. Nó không thích hợp cho các bảng được cập nhật nhiều nhất - như bảng của bạn.
Tệ hơn, truy vấn sử dụng chỉ mục này mất gấp hai lần miễn là truy vấn ban đầu của bạn và ở mức tốt nhất một nửa là dài trên cùng một tập dữ liệu. Đó là điều tồi tệ nhất đối với các trường hợp chỉ số không phải là rất có chọn lọc như ARRAY[1]
- 4s so với 2 giây đối với truy vấn ban đầu. Trường hợp chỉ số có tính chọn lọc cao (ví dụ: không có nhiều kết quả phù hợp, chẳng hạn như ARRAY[199]
), chỉ số này chạy trong khoảng 1,2 giây so với 3 giây ban đầu. Chỉ mục này chỉ đơn giản là không có giá trị cho truy vấn này.
Bài học ở đây? Đôi khi, câu trả lời đúng chỉ là thực hiện quét tuần tự.
Vì điều đó sẽ không làm cho tỷ lệ truy cập của bạn, hãy duy trì chế độ xem được kích hoạt bằng @debenhur gợi ý hoặc cố gắng đảo ngược mảng thành danh sách các thông số mà mục nhập không phải có thể sử dụng chỉ mục GiST như @maniek đề xuất.
Không chắc chắn, nhưng tôi nghĩ rằng chỉ mục GIN trên table.array_column sẽ giúp tăng tốc độ này. Bạn sẽ cần phải chạy EXPLAIN để tìm hiểu. Xem ở đây: http://dba.stackexchange.com/a/27505/1822 –
Sẽ rất khó để thực hiện điều này hiệu quả trong các postgres khi bảng trở nên lớn. chỉ mục gin sẽ chỉ giúp khi thử nghiệm "chứa trong" trái với "không chứa trong" trong vị từ của bạn. Nếu nó không quan trọng là đếm được chính xác 100%, bạn có thể thử bộ nhớ đệm nó ở lớp ứng dụng với một số TTL. Nếu tỷ lệ ghi của bạn trên bảng không quá cao, bạn có thể sử dụng các trình kích hoạt hợp lý để cập nhật một bảng khác có chứa số lượng hiện tại. – dbenhur
Tốt nhất để hiển thị phiên bản của bạn và 'giải thích phân tích'; xem http://stackoverflow.com/tags/postgresql-performance/info –