문제
다음은 pgsql.general에서 논의 된 매우 유사한 사례 입니다. b-tree 인덱스의 제한 사항에 관한 것이지만 GIN 인덱스는 내부적 으로 키에 b-tree 인덱스를 사용 하므로 일반 b- 트리 의 항목 크기 대신 키 크기에 대해 동일한 제한을 갖기 때문에 모두 동일합니다. 인덱스).
GIN 인덱스 구현에 대한 매뉴얼을 인용하십시오 .
내부적으로 GIN 인덱스에는 키에 대해 구성된 B- 트리 인덱스가 포함되어 있습니다. 여기서 각 키는 하나 이상의 인덱싱 된 항목의 요소입니다.
어느 쪽이든, 열에서 하나 이상의 배열 요소data
가 너무 커서 색인을 생성 할 수 없습니다. 이것이 단수의 괴물 값이거나 어떤 종류의 사고 일 경우 값을 자르고 끝낼 수 있습니다.
다음 데모의 목적을 위해 다른 방법으로 가정합니다. 배열에 긴 텍스트 값이 많이 있습니다.
간단한 솔루션
배열의 요소를 해시 값data
에 따라 바꿀 수 있습니다 . 동일한 해시 함수를 통해 조회 값을 보냅니다. 물론 어딘가에 원본을 저장하고 싶을 수도 있습니다. 그것으로, 우리는 거의 두 번째 변형에 도착합니다 ...
고급 솔루션
serial
대리 기본 키 (효과적으로 근본적인 해시 값)로 열 이있는 배열 요소에 대한 룩업 테이블을 만들 수 있습니다. 관련 요소 값이 고유하지 않은 경우 더욱 흥미 롭습니다.
CREATE TABLE elem (
elem_id serial NOT NULL PRIMARY KEY
, elem text UNIQUE NOT NULL
);
우리가보고 싶은 때문에 elem
- 우리는 인덱스 추가 하지만 식에 인덱스를 전용으로, 이번에 처음 10 개 문자 긴 텍스트의 색입니다. 대부분의 경우 검색 범위를 하나 또는 몇 개의 검색 범위로 좁히기에 충분합니다. 데이터 배포에 맞게 크기를 조정하십시오. 또는보다 정교한 해시 함수를 사용하십시오.
CREATE INDEX elem_elem_left10_idx ON elem(left(elem,10));
그러면 열 data
이 유형이 int[]
됩니다. 나는 테이블의 이름을 바꾸고 귀하의 예에서 data
불길한 varchar(50)
것을 제거했습니다 .
CREATE TEMP TABLE data(
data_id serial PRIMARY KEY
, data int[]
);
의 각 배열 요소는을 data
나타냅니다 elem.elem_id
. 이 시점에서 배열 열을 n : m 테이블로 바꾸어 스키마를 정규화하고 Postgres가 참조 무결성을 강화하도록 고려할 수 있습니다. 인덱싱 및 일반 처리가 쉬워집니다 ...
그러나 성능상의 이유로 int[]
GIN 인덱스와 결합 된 컬럼이 우수 할 수 있습니다. 스토리지 크기가 훨씬 작습니다. 이 경우 GIN 인덱스가 필요합니다.
CREATE INDEX data_data_gin_idx ON data USING GIN (data);
이제 GIN 인덱스의 각 키 (= 배열 요소)는 long integer
대신입니다 text
. 색인은 몇 자릿수 씩 작아지며 결과적으로 검색 속도 가 훨씬 빨라집니다.
단점 : 실제로 검색을 수행하기 전에 elem_id
테이블에서 를 찾아야 합니다 elem
. 새로 도입 된 기능 색인을 사용하면 elem_elem_left10_idx
훨씬 빠릅니다.
하나의 간단한 쿼리로 모든 작업을 수행 할 수 있습니다 .
SELECT d.*, e.*
FROM elem e
JOIN data d ON ARRAY[e.elem_id] <@ d.data
WHERE left(e.elem, 10) = left('word1234word', 10) -- match index condition
AND e.elem = 'word1234word'; -- need to recheck, functional index is lossy
intarray
추가 연산자 및 연산자 클래스를 제공 하는 확장 기능에 관심이있을 수 있습니다 .
data
에서 시연 한 것과 같은 태그 목록 이 포함되어 있을 수 있습니까? 이 경우 더 나은 솔루션이있을 수 있습니다.