PostgreSQL có thể lập chỉ mục các cột mảng?


144

Tôi không thể tìm thấy câu trả lời chắc chắn cho câu hỏi này trong tài liệu. Nếu một cột là một kiểu mảng, tất cả các giá trị được nhập sẽ được lập chỉ mục riêng?

Tôi đã tạo một bảng đơn giản với một int[]cột và đặt một chỉ mục duy nhất trên đó. Tôi nhận thấy rằng tôi không thể thêm cùng một mảng ints, điều này khiến tôi tin rằng chỉ mục là 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");

Là chỉ số giúp truy vấn này?


Có thể sử dụng kiểu dữ liệu jsonbvà sử dụng các chỉ mục? postgresql.org/docs/9.5/static/fifts-json.htmlpostgresql.org/docs/9.5/static/datatype-json.html#JSON-INDEXING
user3791372

Câu trả lời:


179

Có, bạn có thể lập chỉ mục một mảng, nhưng bạn phải sử dụng các toán tử mảngloại chỉ mục GIN .

Thí 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
Ghi chú

có vẻ như trong nhiều trường hợp, tùy chọn gin__int_ops là bắt buộc

create index <index_name> on <table_name> using GIN (<column> gin__int_ops)

Tôi chưa thấy trường hợp nào nó hoạt động với toán tử && và @> mà không có tùy chọn gin__int_ops


19
Khi OP phỏng đoán, điều này thực sự không lập chỉ mục các giá trị mảng riêng lẻ, mà thay vào đó lập chỉ mục cho toàn bộ mảng. Vì vậy, trong khi điều này sẽ giúp truy vấn được đề cập (xem kế hoạch giải thích), điều này có nghĩa là bạn không thể tạo 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" để lập 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 đối với giá trị văn bản này, nhưng những người đóng góp có thể được hoan nghênh để giúp hoàn thành nó).
xzilla

15
Vui lòng không sử dụng chữ in hoa trong số nhận dạng PostgreQuery 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 quy tắc gấp trích dẫn / trường hợp, đặc biệt là những người mới sử dụng PostgreQuery.
intgr

6
Để 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 rất ít hoặc không tăng tốc trừ khi gin__int_ops được sử dụng cho integer[]các cột. 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 op này. Đó là một nhân viên kỳ diệu biên giới.
IamIC

1
@IamIC có nghĩa là tôi không nên lập chỉ mục một chuỗi các chuỗi? Và tôi chỉ nên lập chỉ mục mảng số nguyên?
ryan2johnson9

93

@Tregoreg đưa ra một câu hỏi trong bình luận cho tiền thưởng được cung cấp 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 gõ mảng không làm tăng hiệu suất của toán tử ANY (). Có thực sự không có giải pháp?

Câu trả lời được chấp nhận của @ Frank cho bạn biết sử dụng toán tử mảng , vẫn đúng cho Postgres 11. Hướng dẫn:

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

<@
@>
=
&&

Danh sách đầy đủ các lớp toán tử tích hợp cho các chỉ mục GIN trong phân phối chuẩn có ở đây.

Trong Postgres, các chỉ mục được ràng buộc với các toán tử (được triển khai cho một số loại nhất định), không chỉ các loại dữ liệu hoặc các hàm hoặc bất cứ thứ gì khác. Đó là một di sản từ thiết kế Postgres ban đầu của Berkeley và rất khó thay đổi. Và nó thường hoạt động tốt. Dưới đây là một chủ đề về lỗi pssql với Tom Lane bình luận về điều này.

Một số PostGis chức năng (như ST_DWithin()) dường như vi phạm hiệu trưởng này, nhưng thực tế không phải vậy. Các chức năng này được viết lại trong nội bộ để sử dụng các toán tử tương ứng .

Biểu thức được lập chỉ mục phải ở 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 trường hợp trên ), trình hoạch định 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 - với điều kiện là COMMUTATORđã được xác định. CácANY trúc có thể được sử dụng kết hợp với các toán tử khác nhau và bản thân nó không phải là toán tử. Khi được sử dụng như constant = ANY (array_expression)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 ta sẽ cần một cổ góp cho = ANY(). Chỉ số GIN được đưa ra.

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

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

Ngoài ra

Trong khi làm việc với integercác mảng ( int4, không int2hoặc int8) không có NULLgiá trị (như ví dụ của bạn ngụ ý), hãy xem xét mô-đun bổ sung intarray, cung cấp các toán tử chuyên biệt, nhanh hơn và hỗ trợ chỉ mục. Xem:

Đối với các UNIQUEràng buộc trong câu hỏi của bạn chưa được trả lời: Điều đó được thực hiện với chỉ số btree trên toàn bộ giá trị mảng (như bạn nghi ngờ) và hoàn toàn không giúp tìm kiếm các phần tử . Chi tiết:


1
Aaaaaaah, cảm thấy khá xấu hổ ngay bây giờ, nhưng tôi không nghĩ rằng những người đăng bài sẽ không sử dụng chỉ số ngay cả khi về mặt lý thuyết là có thể. Có lẽ đó cũng là vì sự thiếu hiểu biết của tôi về postgres, chẳng hạn như các chỉ số đó bị ràng buộc với các nhà khai thác. Cảm ơn bạn đã dành thời gian để trả lời câu hỏi không hay 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ớ bản thân đã bị nhầm lẫn bởi điều này khi lần đầu tiên tôi gặp phải nó. Câu hỏi được thêm vào và làm rõ nên khá hữu ích cho công chúng.
Erwin Brandstetter

1
Từ kinh nghiệm của tôi, các chỉ mục này cung cấp rất ít hoặc không tăng tốc trừ khi gin__int_ops được sử dụng cho integer[]các cột. 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 op này. Đó là một nhân viên kỳ diệu biên giới.
IamIC

2
@IamIC: Tôi đã thêm con trỏ vào intarray. Có vẻ đáng chú ý, như bạn đã chỉ ra.
Erwin Brandstetter

Đối với ANY (array_expression) = constantbiểu thức, chỉ mục GIN hoạt động tốt?
dùng10375

37

Bây giờ có thể lập chỉ mục các thành phần mảng riêng lẻ. 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 cho từng chỉ mục mảng, trong ví dụ của tôi, tôi chỉ lập chỉ mục cho phần tử đầu tiên.


28
Để nó không bị mất - cách tiếp cận này là vô vọng đối với mảng có chiều dài thay đổi nơi bạn muốn sử dụng toán tử ANY ().
Καrτhικ

24
Điều này thực sự không hữu ích lắm. 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 từng 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 hơn cho từng mục mảng. Lưu trữ các cột riêng lẻ rẻ hơn nhiều mà không có chi phí mảng.
Erwin Brandstetter
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.