F.17. intarray

intarray 모듈은 정수를 구성 요소로 하는 null 값이 없는 배열 처리를 위한 유용한 함수와 연산자를 제공한다. 또한 이 배열 자료형에 대한 인덱스 검색 기능도 제공한다.

참고: 8.2 버전에서 모든 배열 자료형에 대한 부분 배열 검색에서 인덱스를 사용할 수 있도록 내장 연산자를 제공한다. (@>, <@, &&) 정수형 배열 조작을 위한 여러 함수를 쓰기 위해 이 모듈은 아직 부가 모듈로 분리되어 있다 - 옮긴이

여기서 소개하는 모든 연산자는 그 대상 배열에 null 값이 있으면, 오류를 낸다.

여기서 소개하는 대부분의 연산자는 일차원 배열에서만 쓸모가 있다. 물론 다차원 배열에서도 사용 가능 하지만, 그 자료는 저장 순서를 기반으로 일차원 배열처럼 간주한다.

F.17.1. intarray 함수와 연산자들

intarray 모듈에서 제공하는 함수는 표 F-8에서, 연산자는 표 F-9에서 소개한다.

표 F-8. intarray 함수들

함수반환 자료형설명사용예결과
icount(int[])int배열 요소 개수icount('{1,2,3}'::int[])3
sort(int[], text dir)int[]배열 정렬 — dir에는 asc 또는 desc만 허용sort('{1,2,3}'::int[], 'desc'){3,2,1}
sort(int[])int[]오름차순 정렬sort(array[11,77,44]){11,44,77}
sort_asc(int[])int[]오름차순 정렬
sort_desc(int[])int[]내림차순 정렬
uniq(int[])int[]중복된 요소 제거uniq(sort('{1,2,3,2,1}'::int[])){1,2,3}
idx(int[], int item)int해당 item 요소가 배열의 몇번째에 있는지 (0이면 없음)idx(array[11,22,33,22,11], 22)2
subarray(int[], int start, int len)int[]배열의 start 시작 위치에서, len 개수 만큼 부분 배열 추출subarray('{1,2,3,2,1}'::int[], 2, 3){2,3,2}
subarray(int[], int start)int[]배열의 start 번째부터 시작해서 끝까지 부분 배열 추출subarray('{1,2,3,2,1}'::int[], 2){2,3,2,1}
intset(int)int[]입련 인자를 단일 요소로 하는 배열 반환intset(42){42}

표 F-9. intarray 연산자들

연산자반환값설명
int[] && int[]boolean겹침 — 두 배열 요수 가운데 한 요소라도 같으면 true
int[] @> int[]boolean포함함 — 왼쪽 배열이 오른쪽 배열을 포함하면 true
int[] <@ int[]boolean포함됨 — 왼쪽 배열이 오른쪽 배열에 포함되면 true
# int[]int배열 요소 수
int[] # intintidx 함수의 연산자
int[] + intint[]배열에 요소 추가 (배열 마지막에 추가됨)
int[] + int[] int[]배열 합치기, 왼쪽 오른쪽 순서대로 합침
int[] - intint[]오른쪽에 지정한 정수가 배열 요소에 있으면 뺌
int[] - int[]int[]왼쪽 배열에서 오른쪽 배열 요소들을 모두 뺌
int[] | intint[]오른쪽 정수를 왼쪽 배열에 포함함 (이미 있으면 무시)
int[] | int[]int[]두 배열을 합치면서 겹치는 것 없앰
int[] & int[]int[]두 배열의 교집합
int[] @@ query_intboolean해당 query_int 조건에 맞으면 true (아래 참조)
query_int ~~ int[]boolean@@ 연산자의 교환 연산자

(8.2 이전 버전에서는 @> 연산자와 <@ 연산자는 각각 @, ~ 로 사용했었다. 이 연산자들도 아직 사용할 수는 있지만, 범용 배열 연산자들이 정리되면서 이 연산자(@,~)는 이제 더 이상 사용하지 않는다. 이 연산자들은 기본 지리정보 자료형에서 아직 사용하기에, 헷갈리지 않기 바란다!)

&&, @>, <@ 연산자는 범용 배열 자료형의 기본 연산자로 채택되어 그 사용법이 똑같다. 다른 점은 이 모듈을 사용하면, 정수형 배열에서는 null 값이 없어야되고, 그 외 배열 자료형에서는 null 값이 있어도 된다. 이런 제한은 정수형 배열 자료형에서 처리 속도를 빠르게 하기 때문에, 아직까지 이런 차이가 있다.

@@, ~~ 연산자는 지정한 쿼리 조건에 만족하는가를 검사하는 연산자다. 이 쿼리는 문자열로 query_int 구문을 사용해야 하면, 사용할 수 있는 기호는 & (AND), | (OR), ! (NOT) 이다. 예를 들어 이 쿼리가 1&(2|3) 이라면, 해당 배열 요소들 가운데, 1은 반드시 있어야 하고, 2 또는 3도 반드시 있는 배열이면 이 연산자는 true를 반환한다.

F.17.2. 인덱스 지원

intarray 모듈은 &&, @>, <@, @@ 연산자를 사용할 경우 인덱스를 사용해서 보다 빠르게 그 결과를 확인할 수 있도록 연산자 클래스를 제공한다.

GiST 색인 방법으로 다음 두 가지 연산자 클래스를 제공한다: gist__int_ops (기본값) 클래스는 4바이트 정수 최대값 만큼의 배열 요소가 있는 경우, gist__intbig_ops 클래스는 8바이트 정수 최대값 만큼의 배열 요소가 있는 경우에 사용한다. 이 색인 방법은 RD-tree 자료 구조에 대한 구현체이며, 내장된 압축이 별로 안되는 방법이다.

참고: gist__int_ops, gist__intbig_ops 연산자 클래스는 정수형 배열의 요소 개수에 따른 구분이지, 그 정수 자료형은 모두 int4 형이다. int8 형 배열에 대한 인덱스는 PostgreSQL 기본 배열 인덱스를 이용하면 된다 - 옮긴이

GIN 연산자 클래스로 gin__int_ops 연산자 클래스도 제공한다.

해당 배열형에 대해서 GiST 색인 방법을 쓸지, GIN 색인 방법을 쓸지에 대해서는 Gist, GIN 인덱스의 장단점을 충분히 파악한 후 선택하면 된다. 간략하게 소개하면, 일단 검색 속도는 GIN 색인 방법이 더 빠르지만, 자료 입력, 변경 속도는 GiST 보다 느리다. 그래서, 읽기 전용 자료라면, GIN 색인 방법을, 자주 그 배열 자료가 바뀐다면 GiST 색인 방법을 사용하면 된다. (물론 실재로는 이처럼 단순하지는 않다. 자세한 이야기는 59, 61장 참조 - 옮긴이)

F.17.3. 사용 예

-- 하나의 메시지는 하나 또는 여러 섹션을 포함한다.
CREATE TABLE message (mid INT PRIMARY KEY, sections INT[], ...);

-- sections 칼럼에 대한 인덱스
CREATE INDEX message_rdtree_idx ON message USING GIST (sections gist__int_ops);

-- 겹침 연산자를 이용한 해당 섹션이 있는 메시지 찾기
SELECT message.mid FROM message WHERE message.sections && '{1,2}';

-- 포함 연산자를 이용한 해당 섹션이 있는 메시지 찾기
SELECT message.mid FROM message WHERE message.sections @> '{1,2}';

-- 윗 쿼리와 같은 쿼리 문자열을 이용한 또 다른 방법
SELECT message.mid FROM message WHERE message.sections @@ '1&2'::query_int;

F.17.4. 성능 검사

소스 디렉터리 안 contrib/intarray/bench 디렉터리에 이 모듈에 대한 성능 검사 관련 소스들이 포함되어 있다. 사용법:

cd .../bench
createdb TEST
psql TEST < ../_int.sql
./create_test.pl | psql TEST
./bench.pl

bench.pl 스크립트는 다양한 옵션을 제공한다. 옵션 설명은 아무런 옵션 없이 실행하면 보여준다.

F.17.5. 만든이

모든 작업은 Teodor Sigaev ()와 Oleg Bartunov ()가 했다. 추가적인 정보는 http://www.sai.msu.su/~megera/postgres/gist/ 페이지에서 제공한다. Andrey Oktyabrski가 새 함수와 연산자들 추가 작업을 했다.