Innovating today, leading tomorrow

OpenSQL_Technical Guide
[OpenSQL] Contrib Extensions – 인덱스 및 검색

[OpenSQL] Contrib Extensions – 인덱스 및 검색

Contrib Extensions – 인덱스 및 검색

Contrib Extension에서 인덱스와 검색기능을 보완하는 기능을 제공하는 Extension을 모아서 정리해봤습니다.

  • bloom
  • dict_xsyn
  • dict_int

bloom

bloom 필터를 기반으로 하는 인덱스 액세스 방법을 제공합니다. bloom 필터란 구성요소가 집합의 구성원인지 여부를 테스트하는데 사용되는 공간 효율적인 데이터 구조입니다. 이 유형의 인덱스는 테이블에 많은 속성이 있고, 쿼리가 속성의 임의 조합을 테스트할 때 가장 유용합니다. btree 인덱스가 bloom보다 빠르지만, 단일 bloom 인덱스만 필요한 쿼리를 지원하려면 많은 btree가 필요할 수 있습니다.
bloom 인덱스는 with 절에서 다음 매개변수를 허용합니다.

매개변수설명
length각 색인 항목의 길이(bit단위). 16의 가장 가까운 배수로 반올림. default 80, max 4096
col1 ~ col32각 인덱스 컬럼에 대해 생성된 비트 수. 각 매개변수의 이름은 해당 매개변수가 제어하는 인덱스 열의 번호. default 2bit, max 4095. 실제로 사용되지 않는 인덱스 컬럼의 매개변수는 무시.

또한 bloom 인덱스에 대한 연산자 클래스는 인덱싱된 데이터 유형에 대한 해시함수와, 검색을 위한 등호 연산자만 필요합니다.

예시

간단하게 bloom인덱스를 생성하는 예시와 임의의 테이블로 bloom 인덱스를 사용하기 좋은 상황의 예시입니다.’

  • bloom 인덱스 생성 예시 구문

CREATE INDEX bloomidx ON tbloom USING bloom (i1,i2,i3)
WITH (length=80, col1=2, col2=2, col3=4);
–index는 80 bit의 길이로 생성되며 속성 i1 및 i2는 2bit, i3은 4bit에 매핑됩니다.
–default 값은 생략 가능합니다.

  • bloom 인덱스 사용 예시 및 btree 인덱스 보다 성능이 더 나오는 예시

예시 테이블 생성

CREATE TABLE tbloom AS
SELECT
(random() * 1000000)::int as i1,
(random() * 1000000)::int as i2,
(random() * 1000000)::int as i3,
(random() * 1000000)::int as i4,
(random() * 1000000)::int as i5,
(random() * 1000000)::int as i6
FROM
generate_series(1,10000000);
SELECT 10000000

테이블 생성 후 쿼리 실행 계획

EXPLAIN ANALYZE SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451;

QUERY PLAN

Seq Scan on tbloom (cost=0.00..2137.14 rows=3 width=24) (actual time=16.971..16.971 rows=0 loops=1)
Filter: ((i2 = 898732) AND (i5 = 123451))
Rows Removed by Filter: 100000
Planning Time: 0.346 ms
Execution Time: 16.988 ms
(5 rows)

btree 인덱스 생성 후 index 크기와 실행계획

CREATE INDEX btreeidx ON tbloom (i1, i2, i3, i4, i5, i6);
CREATE INDEX

SELECT pg_size_pretty(pg_relation_size(‘btreeidx’));

pg_size_pretty

3976 kB
(1 row)

EXPLAIN ANALYZE SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451;

QUERY PLAN

Seq Scan on tbloom (cost=0.00..2137.00 rows=2 width=24) (actual time=12.805..12.805 rows=0 loops=1)
Filter: ((i2 = 898732) AND (i5 = 123451))
Rows Removed by Filter: 100000
Planning Time: 0.138 ms
Execution Time: 12.817 ms
(5 rows)

bloom 인덱스 생성 후 index 크기와 실행계획

CREATE INDEX bloomidx ON tbloom USING bloom (i1, i2, i3, i4, i5, i6);
CREATE INDEX

SELECT pg_size_pretty(pg_relation_size(‘bloomidx’));

pg_size_pretty

1584 kB
(1 row)

EXPLAIN ANALYZE SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451;

QUERY PLAN

Bitmap Heap Scan on tbloom (cost=1792.00..1799.69 rows=2 width=24) (actual time=0.388..0.388 rows=0 loops=1)
Recheck Cond: ((i2 = 898732) AND (i5 = 123451))
Rows Removed by Index Recheck: 29
Heap Blocks: exact=28
-> Bitmap Index Scan on bloomidx (cost=0.00..1792.00 rows=2 width=0) (actual time=0.356..0.356 rows=29 loops=1)
Index Cond: ((i2 = 898732) AND (i5 = 123451))
Planning Time: 0.099 ms
Execution Time: 0.408 ms
(8 rows)

추가로, btree의 성능을 높이려면 아래와 같이 각 컬럼에 대해 인덱스를 별도로 생성해야 합니다.

CREATE INDEX btreeidx1 ON tbloom (i1);
CREATE INDEX
CREATE INDEX btreeidx2 ON tbloom (i2);
CREATE INDEX
CREATE INDEX btreeidx3 ON tbloom (i3);
CREATE INDEX

CREATE INDEX btreeidx6 ON tbloom (i6);
CREATE INDEX
EXPLAIN ANALYZE SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451;

QUERY PLAN

Bitmap Heap Scan on tbloom (cost=24.34..32.03 rows=2 width=24) (actual time=0.028..0.029 rows=0 loops=1)
Recheck Cond: ((i5 = 123451) AND (i2 = 898732))
-> BitmapAnd (cost=24.34..24.34 rows=2 width=0) (actual time=0.027..0.027 rows=0 loops=1)
-> Bitmap Index Scan on btreeidx5 (cost=0.00..12.04 rows=500 width=0) (actual time=0.026..0.026 rows=0 loops=1)
Index Cond: (i5 = 123451)
-> Bitmap Index Scan on btreeidx2 (cost=0.00..12.04 rows=500 width=0) (never executed)
Index Cond: (i2 = 898732)
Planning Time: 0.491 ms
Execution Time: 0.055 ms
(9 rows)

이렇게 구성 시 성능은 확실하게 나오지만, 인덱스 사이즈가 너무 커져서(각 컬럼별 인덱스마다 2MB) bloom을 사용할 경우보다 8배의 공간을 차지하게 됩니다.

참고 사이트

dict_xsyn

전체 텍스트 검색을 위한 추가 사전 템플릿의 예입니다. 이 사전 유형은 단어를 동의어 그룹으로 대체하므로 동의어를 사용하여 단어를 검색할 수 있습니다.

dictionary에는 다음과 같은 옵션을 사용합니다.

옵션설명
matchorig원래 단어가 사전에서 허용되는지 여부를 제어. default true
matchsynonyms동의어가 사전에서 허용되는지 여부를 제어. default true
keeporig원래 단어가 사전의 출력에 포함되는지 여부를 제어. default true
keepsynonyms동의어가 사전의 출력에 포함되는지 여부를 제어. default true
rules동의어 목록이 포함된 파일의 기본 이름.
이 파일은 $SHAREDIR/tsearch_data 위치에 저장($SHAREDIR은 /usr/pgsql-14/share경로처럼 PostgreSQL 공유 데이터 디렉토리.).
이름은 .rules로 끝나야 하고 rules 내용은 word syn1 syn2 syn3 와 같이 작성됩니다. ex)supernova sn sne 1987a

예시

다음은 dict_xsyn 구문의 예시와 각 옵션을 활용했을 경우 결과의 예시입니다.

ALTER TEXT SEARCH DICTIONARY xsyn (RULES=’xsyn_sample’, KEEPORIG=true, MATCHORIG=true, KEEPSYNONYMS=true, MATCHSYNONYMS=false);

–이미 작성된 xsyn_sample의 supernova단어에 대한 동의어들이 같이 조회됩니다.
SELECT ts_lexize(‘xsyn’, ‘supernova’);

ts_lexize

{supernova,sn,sne,1987a}
(1 row)

–matchsynonyms옵션이 false라 조회되지 않습니다.
SELECT ts_lexize(‘xsyn’, ‘sn’);

ts_lexize

(1 row)

–전혀다른 단어라 당연히 조회되지 않습니다.
SELECT ts_lexize(‘xsyn’, ‘grb’);

ts_lexize

(1 row)

–동의어만 조회됩니다.
ALTER TEXT SEARCH DICTIONARY xsyn (RULES=’xsyn_sample’, KEEPORIG=false, MATCHORIG=true, KEEPSYNONYMS=true, MATCHSYNONYMS=false);

SELECT ts_lexize(‘xsyn’, ‘supernova’);

ts_lexize

{sn,sne,1987a}
(1 row)

–동의어 입력시 같이 조회됩니다.
ALTER TEXT SEARCH DICTIONARY xsyn (RULES=’xsyn_sample’, KEEPORIG=true, MATCHORIG=true, KEEPSYNONYMS=true, MATCHSYNONYMS=true);

SELECT ts_lexize(‘xsyn’, ‘supernova’);

ts_lexize

{supernova,sn,sne,1987a}
(1 row)

SELECT ts_lexize(‘xsyn’, ‘sn’);

ts_lexize

{supernova,sn,sne,1987a}
(1 row)

참고 사이트

dict_int

dict_int는 전체 텍스트 검색을 위한 add-on 사전 템플릿의 예시입니다. 이 사전이 만들어진 동기는 정수(signed 및 unsigned)의 인덱싱을 제어하여 검색 성능에 큰 영향을 미치는 고유한 단어 수의 과도한 증가를 방지하면서 이러한 숫자가 인덱싱되도록 하는 것입니다.

이 사전은 세가지 옵션을 허용합니다.

  • maxlen 매개변수는 정수 단어에 허용되는 최대 자릿수를 지정합니다. default는 6입니다.
  • rejectlong 매개변수는 길이가 긴 정수를 자르거나 무시할지 여부를 지정합니다. default 값은 false이며, 이 경우 사전은 정수의 첫번째 maxlen 숫자를 반환합니다. true일 경우 길이가 초과된 정수를 중지 단어로 처리하므로 index가 생성되지 않습니다.
  • absval 매개변수는 정수 단어에서 선행 “+” 또는 “-” 기호를 제거해야하는지 여부를 지정합니다. default는 false이며, true인 경우 maxlen이 적용되기 전에 기호가 제거됩니다.

예시

각 옵션별로 활용하는 예시입니다.

ALTER TEXT SEARCH DICTIONARY intdict (MAXLEN = 6.7);
–‘+’기호 포함 최대자릿수 6.7자리라 6자리인 +40865까지 출력됨을 확인
select ts_lexize(‘intdict’, ‘+40865854’);

ts_lexize

{+40865}
(1 row)

ALTER TEXT SEARCH DICTIONARY intdict (ABSVAL = true);
— MAXLEN 6.7 + ABSVAL true 옵션으로, 기호를 제거하고 408658까지 출력됨을 확인
select ts_lexize(‘intdict’, ‘-40865854’);

ts_lexize

{408658}
(1 row)

ALTER TEXT SEARCH DICTIONARY intdict (REJECTLONG = 1);
— MAXLEN 6.7 + ABSVAL 처리를 해도 길이초과로 데이터가 출력되지 않음
select ts_lexize(‘intdict’, ‘-40865854’);

ts_lexize

{}
(1 row)

— MAXLEN 6.7 + ABSVAL 처리시 길이가 맞아서 데이터 출력됨
select ts_lexize(‘intdict’, ‘-408658’);

ts_lexize

{408658}
(1 row)

참고 사이트

지금까지 ‘PostgreSQL의 Contrib Extensions – 인덱스 및 검색’에 관해 알아보았습니다

‘PostgreSQL의 pgcryto’를 바로 이어서 확인해보세요!

광고성 정보 수신

개인정보 수집, 활용 목적 및 기간

(주)티맥스티베로의 개인정보 수집 및 이용 목적은 다음과 같습니다.
내용을 자세히 읽어보신 후 동의 여부를 결정해 주시기 바랍니다.

  • 수집 목적: 티맥스티베로 뉴스레터 발송 및 고객 관리
  • 수집 항목: 성함, 회사명, 회사 이메일, 연락처, 부서명, 직급, 산업, 담당업무, 관계사 여부, 방문 경로
  • 보유 및 이용 기간: 동의 철회 시까지

※ 위 개인정보 수집 및 이용에 대한 동의를 거부할 권리가 있습니다.
※ 필수 수집 항목에 대한 동의를 거부하는 경우 뉴스레터 구독이 제한될 수 있습니다.

개인정보의 처리 위탁 정보
  • 업체명: 스티비 주식회사
  • 위탁 업무 목적 및 범위: 광고가 포함된 뉴스레터 발송 및 수신자 관리
 

개인정보 수집 및 이용

개인정보 수집, 활용 목적 및 기간

(주)티맥스티베로의 개인정보 수집 및 이용 목적은 다음과 같습니다. 내용을 자세히 읽어보신 후 동의 여부를 결정해 주시기 바랍니다.

  • 수집 목적: 티맥스티베로 뉴스레터 발송 및 고객 관리
  • 수집 항목: 성함, 회사명, 회사 이메일, 연락처, 부서명, 직급, 산업, 담당업무, 관계사 여부, 방문 경로
  • 보유 및 이용 기간: 동의 철회 시까지

※ 위 개인정보 수집 및 이용에 대한 동의를 거부할 권리가 있습니다.
※ 필수 수집 항목에 대한 동의를 거부하는 경우 뉴스레터 구독이 제한될 수 있습니다.

개인정보의 처리 위탁 정보

  • 업체명: 스티비 주식회사
  • 위탁 업무 목적 및 범위: 광고가 포함된 뉴스레터 발송 및 수신자 관리
  •