PostgreSQL이 배열 열을 색인 할 수 있습니까?


144

설명서 에서이 질문에 대한 명확한 대답을 찾을 수 없습니다. 열이 배열 유형 인 경우 입력 한 모든 값이 개별적으로 색인화됩니까?

하나의 int[]열이 있는 간단한 테이블을 만들고 고유 한 인덱스를 넣었습니다. 동일한 int 배열을 추가 할 수 없다는 것을 알았습니다. 따라서 색인은 각 항목의 색인이 아닌 배열 항목의 합성이라고 생각하게됩니다.

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

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

색인이이 쿼리에 도움이됩니까?


데이터 유형 jsonb을 사용하고 인덱스를 사용할 수 있습니까? postgresql.org/docs/9.5/static/functions-json.htmlpostgresql.org/docs/9.5/static/datatype-json.html#JSON-INDEXING
user3791372

답변:


181

예, 배열을 인덱싱 할 수 있지만 배열 연산자GIN- 인덱스 유형 을 사용해야합니다 .

예:

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

결과:

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
노트

많은 경우 gin__int_ops 옵션이 필요한 것으로 보입니다.

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

gin__int_ops 옵션없이 && 및 @> 연산자와 함께 작동하는 경우를 아직 보지 못했습니다.


19
OP가 예상하는대로 실제로는 개별 배열 값을 인덱싱하지 않고 전체 배열을 인덱싱합니다. 따라서 문제의 쿼리에 도움이되지만 (설명 계획 참조) 개별 배열 값에 대해 고유 한 제약 조건을 쉽게 만들 수는 없습니다. 즉, 정수 배열을 사용하는 경우 contrib 모듈 "intarray"를 사용하여 개별 배열 값을 인덱싱 할 수 있으며,이 경우 많은 경우 훨씬 빠릅니다. (IIRC는 텍스트 값에 대해이 작업을 수행하고 있지만 기고자들은 마무리 작업을 도울 수 있습니다.)
xzilla

15
코드 예제에서 PostgreSQL 식별자에 대문자를 사용하지 마십시오. 인용 / 케이스 접힘 규칙에 익숙하지 않은 사람들, 특히 PostgreSQL을 처음 사용하는 사람들을 혼란스럽게합니다.
intgr

6
내 의견을 반복하기 위해 : 내 경험상,이 색인은 열에 사용 되지 않으면 속도가 거의 또는 전혀 향상 되지 않습니다 . 이 op 클래스를 발견 할 때까지 몇 년 동안 좌절과 다른 해결책을 찾았습니다. 국경선 기적의 일꾼입니다. gin__int_opsinteger[]
IamIC

1
@IamIC는 문자열 배열을 인덱싱하지 않아야한다는 것을 의미합니까? 그리고 정수 배열 만 색인해야합니까?
ryan2johnson9

93

@Tregoreg는 제안 된 현상금에 대한 의견에서 질문 을 제기했습니다 .

현재 답변이 작동하지 않습니다. 배열 유형 컬럼에서 GIN 인덱스를 사용하면 ANY () 연산자의 성능이 향상되지 않습니다. 실제로 해결책이 없습니까?

@ 프랭크의 허용 대답은 사용 할 것을 배열 연산자 인, 아직 정확한 포스트 그레스 (11)에 대한 매뉴얼 :

... PostgreSQL의 표준 배포에는 다음 연산자를 사용하여 인덱스 된 쿼리를 지원하는 배열에 대한 GIN 연산자 클래스가 포함되어 있습니다.

<@
@>
=
&&

표준 배포판의 GIN 인덱스에 대한 내장 연산자 클래스의 전체 목록은 다음과 같습니다.

Postgres에서 색인은 데이터 유형이나 함수 또는 다른 것이 아닌 연산자 (특정 유형에 대해 구현 됨)에 바인딩됩니다 . 그것은 Postgres의 원래 버클리 디자인의 유산 이며 지금은 변경하기가 매우 어렵습니다. 그리고 그것은 일반적으로 잘 작동합니다. Tom Lane이 pgsql-bugs에 대한 주석을 작성했습니다.

(와 같은 ) 일부 PostGis 함수는ST_DWithin() 이 원칙을 위반하는 것으로 보이지만 그렇지 않습니다. 이러한 함수는 각 연산자 를 사용하기 위해 내부적으로 다시 작성 됩니다.

색인화 된 표현식은 연산자 의 왼쪽 에 있어야합니다 . 위의 모든 것을 포함하여 대부분의 연산자의 경우 인덱스 플래너를 정의한대로 오른쪽에 배치하면 쿼리 플래너가 피연산자를 뒤집어이를 달성 할 수 있습니다 COMMUTATOR. ANY구조체는 다양한 연산자 병용 조작자 자체 없다 할 수있다. 배열 요소constant = ANY (array_expression) 에서 =연산자를 지원하는 인덱스로만 사용될 경우에 대한 정류자가 필요합니다 . GIN 지수가 부족합니다.= ANY()

Postgres는 현재 GIN- 인덱싱 가능한 표현을 도출 할만큼 똑똑하지 않습니다. 우선, constant = ANY (array_expression)이다 완전히 동일하지array_expression @> ARRAY[constant]. NULL 요소 가 관련된 경우 배열 연산자는 오류를 반환 하지만 ANY구문은 양쪽에서 NULL을 처리 할 수 ​​있습니다. 그리고 데이터 유형 불일치에 대해 다른 결과가 있습니다.

관련 답변 :

옆으로

값이 없는 integer배열 ( int4, not int2또는 int8)을 사용 하는 동안 NULL(예를 들어 암시하는 것처럼) intarray전문적이고 빠른 연산자와 색인 지원을 제공 하는 추가 모듈을 고려하십시오 . 보다:

UNIQUE대답하지 않은 질문 의 제약에 관해서는 : 그것은 전체 배열 값 에 대해 btree 인덱스로 구현되었으며 (예상 한 것처럼) 요소 검색에 전혀 도움이되지 않습니다 . 세부:


1
아 아아아 아아아 아아아 아아아 아아아 아아아 아아아 아아아 아아아 아아아 아아아 아아아 아아아 아아아 아아아 아아아 아아아 아아아 아아아 아아아 아아아 아아악 아 아아아 아아아 아마도 postgres에 대한 통찰력이 부족하기 때문에 지수가 운영자에게 묶여 있기 때문일 수도 있습니다. 잘못된 질문에 답하고 시간을내어 지식을 공유해 주셔서 감사합니다!
Tregoreg

6
@ Tregoreg : 너무 당황하지 마십시오, 너무 명확하지 않습니다. 내가 처음 그것을 만났을 때 나는 이것에 의해 혼란스러워했던 것을 기억한다. 추가 된 질문과 설명은 일반 대중에게 매우 유용해야합니다.
Erwin Brandstetter

1
내 경험상,이 인덱스는 열에 사용 되지 않으면 속도가 거의 또는 전혀 향상 되지 않습니다 . 이 op 클래스를 발견 할 때까지 몇 년 동안 좌절과 다른 해결책을 찾았습니다. 국경선 기적의 일꾼입니다. gin__int_opsinteger[]
IamIC

2
@IamIC : 나는 intarray에 포인터를 추가했습니다. 지적했듯이 주목할만한 것 같습니다.
Erwin Brandstetter

들어 ANY (array_expression) = constant표현, GIN 인덱스는 잘 작동?
user10375

37

이제 개별 배열 요소를 색인화 할 수 있습니다. 예를 들면 다음과 같습니다.

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)

이것은 적어도 Postgres 9.2.1에서 작동합니다. 각 배열 인덱스에 대해 별도의 인덱스를 작성해야합니다.이 예제에서는 첫 번째 요소 만 인덱싱했습니다.


28
이 방법은 ANY () 연산자를 사용하려는 가변 길이 배열에는 적합하지 않습니다.
Καrτhικ

24
이것은 실제로별로 유용하지 않습니다. 고정 된 수의 배열 요소가있는 경우 각 배열 항목에 대해 더 비싼 식 인덱스를 작성하는 대신 각 요소 (및 일반 btree 인덱스)에 대해 개별 열을 사용하는 것이 좋습니다. 개별 열 저장은 어레이 오버 헤드없이 훨씬 저렴합니다.
Erwin Brandstetter 1
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.