2010-10-30 70 views
99

Tôi không thể tìm thấy câu trả lời xác định cho câu hỏi này trong tài liệu. Nếu một cột là một loại mảng, tất cả các giá trị đã nhập có được lập chỉ mục riêng lẻ không?Các cột mảng chỉ mục của PostgreSQL có được không?

Tôi đã tạo một bảng đơn giản với một cột int[] và đặt một chỉ mục duy nhất trên cột đó. Tôi nhận thấy rằng tôi không thể thêm cùng một mảng int, dẫn tôi tin rằng chỉ mục là một tổng hợp của các mục mảng, không phải là chỉ mục của từng mục.

INSERT INTO "Test"."Test" VALUES ('{10, 15, 20}'); 
INSERT INTO "Test"."Test" VALUES ('{10, 20, 30}'); 

SELECT * FROM "Test"."Test" WHERE 20 = ANY ("Column1"); 

Chỉ mục có giúp truy vấn này không?

+0

Có thể sử dụng các kiểu dữ liệu 'jsonb' và sử dụng các chỉ số? https://www.postgresql.org/docs/9.5/static/functions-json.html và https://www.postgresql.org/docs/9.5/static/datatype-json.html#JSON-INDEXING – user3791372

Trả lời

119

Có, bạn có thể lập chỉ mục một mảng, nhưng bạn phải sử dụng array operatorsGIN-index type.

Ví dụ:

CREATE TABLE "Test"("Column1" int[]); 
    INSERT INTO "Test" VALUES ('{10, 15, 20}'); 
    INSERT INTO "Test" VALUES ('{10, 20, 30}'); 

    CREATE INDEX idx_test on "Test" USING GIN ("Column1"); 

    -- To enforce index usage because we have only 2 records for this test... 
    SET enable_seqscan TO off; 

    EXPLAIN ANALYZE 
    SELECT * FROM "Test" WHERE "Column1" @> ARRAY[20]; 

Kết quả:

Bitmap Heap Scan on "Test" (cost=4.26..8.27 rows=1 width=32) (actual time=0.014..0.015 rows=2 loops=1) 
    Recheck Cond: ("Column1" @> '{20}'::integer[]) 
    -> Bitmap Index Scan on idx_test (cost=0.00..4.26 rows=1 width=0) (actual time=0.009..0.009 rows=2 loops=1) 
     Index Cond: ("Column1" @> '{20}'::integer[]) 
Total runtime: 0.062 ms 
+16

Như OP surmises, điều này không thực sự chỉ mục giá trị mảng riêng lẻ, nhưng thay vì chỉ mục toàn bộ mảng. Vì vậy, trong khi điều này sẽ giúp các truy vấn trong câu hỏi (xem giải thích kế hoạch), điều này có nghĩa là bạn không thể tạo ra các ràng buộc duy nhất (dễ dàng) trên các giá trị mảng riêng lẻ. Điều đó nói rằng, nếu bạn đang sử dụng mảng số nguyên, bạn có thể sử dụng mô-đun contrib "intarray" để chỉ mục các giá trị mảng riêng lẻ, có thể nhanh hơn nhiều trong nhiều trường hợp. (IIRC có một số công việc đang được thực hiện về điều này cho các giá trị văn bản, nhưng những người đóng góp có lẽ sẽ được chào đón để giúp hoàn thành nó đi). – xzilla

+6

Vui lòng không sử dụng các chữ hoa trong các định danh PostgreSQL trong các ví dụ mã, nó chỉ gây nhầm lẫn cho những người không quen thuộc với các quy tắc trích dẫn/gấp chữ, đặc biệt là những người mới sử dụng PostgreSQL. – intgr

+1

Để lặp lại nhận xét của tôi ở đây: từ kinh nghiệm của tôi, các chỉ mục này cung cấp ít hoặc không tăng tốc * trừ khi * 'gin__int_ops' được sử dụng cho các cột' số nguyên [] '. Tôi mất nhiều năm thất vọng và tìm kiếm các giải pháp khác cho đến khi tôi phát hiện ra lớp học này. Đó là một công nhân phép màu biên giới. – IamIC

32

Đó là bây giờ có thể chỉ mục các phần tử mảng cá nhân. Ví dụ:

CREATE TABLE test (foo int[]); 
INSERT INTO test VALUES ('{1,2,3}'); 
INSERT INTO test VALUES ('{4,5,6}'); 
CREATE INDEX test_index on test ((foo[1])); 
SET enable_seqscan TO off; 

EXPLAIN ANALYZE SELECT * from test WHERE foo[1]=1; 
               QUERY PLAN              
------------------------------------------------------------------------------------------------------------------ 
Index Scan using test_index on test (cost=0.00..8.27 rows=1 width=32) (actual time=0.070..0.071 rows=1 loops=1) 
    Index Cond: (foo[1] = 1) 
Total runtime: 0.112 ms 
(3 rows) 

Điều này hoạt động trên ít nhất Postgres 9.2.1. Lưu ý rằng bạn cần xây dựng một chỉ mục riêng biệt cho từng chỉ mục mảng, trong ví dụ của tôi, tôi chỉ lập chỉ mục phần tử đầu tiên.

+19

Để nó không bị mất - cách tiếp cận này là vô vọng đối với mảng độ dài thay đổi nơi bạn muốn sử dụng toán tử ANY(). –

+11

Điều này thực sự không phải là rất hữu ích. Nếu bạn có một số phần tử mảng cố định, bạn nên sử dụng các cột riêng lẻ cho mỗi phần tử (và các chỉ số btree đơn giản) thay vì xây dựng một chỉ mục biểu thức đắt tiền hơn cho mỗi mục mảng. Lưu trữ các cột riêng lẻ rẻ hơn rất nhiều mà không cần chi phí mảng. –

58

@Tregoreg nêu ra một câu hỏi trong bình luận cho tiền thưởng chào bán của mình:

tôi không tìm thấy câu trả lời hiện tại làm việc. Sử dụng chỉ mục GIN trên cột được nhập mảng không làm tăng hiệu suất của BẤT CỨ() toán tử. Có thực sự không có giải pháp?

@Frank's accepted answer cho bạn để sử dụng khai thác mảng, đó là vẫn đúng trong 2015.
Per documentation:

phân phối tiêu chuẩn của PostgreSQL bao gồm các lớp điều hành GIN cho mảng một chiều, hỗ trợ các truy vấn được lập chỉ mục sử dụng các toán tử này:

<@ 
@> 
= 
&& 

The complete list of built-in operator classes for GIN indexes in the standard distribution is here.

Trong Postgres chỉ số đang bị ràng buộc để các nhà khai thác, không kiểu dữ liệu hoặc các chức năng hoặc bất cứ điều gì khác. Đó là heritage from the original Berkeley design of Postgres và rất khó thay đổi ngay bây giờ. Và nó thường hoạt động tốt. Here is a thread on pgsql-bugs with Tom Lane commenting on this.

Biểu thức được lập chỉ mục phải là bên trái của toán tử. Đối với hầu hết các toán tử (bao gồm tất cả các bên trên) trình lập kế hoạch truy vấn có thể đạt được điều này bằng cách lật các toán hạng nếu bạn đặt biểu thức được lập chỉ mục sang phải - cho rằng COMMUTATOR đã được xác định.Các ANY construct có thể được sử dụng kết hợp với các nhà khai thác khác nhau và không phải là một nhà điều hành chính nó. Khi được sử dụng làm constant = ANY (array_expression) chỉ các chỉ mục hỗ trợ toán tử = trên các phần tử mảng sẽ đủ điều kiện và chúng tôi sẽ cần một bộ chuyển mạch cho = ANY(). Chỉ số GIN đã hết.

Postgres hiện không đủ thông minh để lấy được biểu thức có thể lập chỉ mục GIN từ đó. Để bắt đầu, constant = ANY (array_expression)không hoàn toàn tương đương đến array_expression @> ARRAY[constant]. Các toán tử mảng trả về lỗi nếu bất kỳ phần tử NULL nào có liên quan, trong khi cấu trúc ANY có thể xử lý NULL ở hai bên. Và có những kết quả khác nhau cho loại dữ liệu không phù hợp.

câu trả lời liên quan:


Đối với UNIQUE hạn chế trong câu hỏi của bạn mà đi chưa được trả lời: Đó là thực hiện với một chỉ số btree trên toàn bộ giá trị mảng (như bạn nghi ngờ) và không giúp đỡ với việc tìm kiếm yếu tố ở tất cả . Thông tin chi tiết:

+0

Aaaaaaah, cảm thấy khá xấu hổ ngay bây giờ, nhưng nó đã không đến với tâm trí của tôi rằng postgres sẽ không sử dụng chỉ số ngay cả khi về mặt lý thuyết có thể.Có lẽ nó cũng vì tôi thiếu hiểu biết về bưu chính, chẳng hạn như các chỉ số đó bị ràng buộc với các toán tử. Cảm ơn bạn đã dành thời gian để trả lời câu hỏi khó chịu của tôi và chia sẻ kiến ​​thức của bạn! – Tregoreg

+6

@Tregoreg: Đừng quá xấu hổ, nó thực sự không quá rõ ràng. Tôi nhớ mình đã bị bối rối khi lần đầu tiên tôi gặp nó. Câu hỏi và làm rõ thêm nên khá hữu ích cho công chúng. –

+0

Từ kinh nghiệm của tôi, các chỉ mục này cung cấp ít hoặc không có tăng tốc * trừ khi * 'gin__int_ops' được sử dụng cho các cột' số nguyên [] '. Tôi mất nhiều năm thất vọng và tìm kiếm các giải pháp khác cho đến khi tôi phát hiện ra lớp học này. Đó là một công nhân phép màu biên giới. – IamIC

Các vấn đề liên quan