역 인덱싱 (Inverted Index)
- Oracle Text(Context Index)가 바로 '역 색인(Inverted Index)' 원리를 이용한 기술임.
- 일반적인 B-Tree 인덱스가 책의 '목차'라면, 역 인덱스는 책 뒷부분의 **'찾아보기(색인)'**와 같습니다.
- 특정 단어가 어느 페이지(RowID)에 있는지 미리 지도로 그려두는 방식임.
역 인덱싱(Inverted Index)의 작동 원리
- 예를들어 5천만건의 대용량 테이블에 Context Index를 생성하면 내부적으로 다음과 같은 구조의 보조 테이블(주로 `$I` 테이블)이 생성됩니다.
: | 토큰(Token) | 문서 ID 리스트 (DocID / RowID) | | --- | --- | | **KIM** | Row1, Row5, Row10... | | **TEST** | Row1, Row2, Row8, Row10... | | **OKOK** | Row3, Row7... |
- 사용자가 `test`를 검색하면, 오라클은 5천만 건의 테이블을 다 읽는 대신 이 **역 인덱스 테이블에서 'TEST'라는 키 값을 찾아 해당 RowID만 콕 집어 가져옵니다.
'부분 일치'를 위한 역 인덱싱 심화 (Bigram / Trigram)
예를들어 데이터가 `=3=3=3=` 이나 `testtest`처럼 단어 경계가 모호한 경우, 일반적인 단어 단위 역 인덱싱으로는 한계가 있습니다. 이때는 **n-gram** 방식을 역 인덱스에 적용해야 합니다.
- **기능:** 문자열을 n글자씩 쪼개서 인덱싱합니다.
- **설정 방법 (Oracle Text 기준):**
BEGIN
-- 데이터를 글자 단위로 쪼개는 LEXER 설정
CTX_DDL.CREATE_PREFERENCE('my_lexer', 'BASIC_LEXER');
CTX_DDL.SET_ATTRIBUTE('my_lexer', 'MIXED_CASE', 'YES'); -- 대소문자 구분 여부
-- 핵심: 단어 중간 검색을 위한 인덱스 데이터 생성 설정
CTX_DDL.CREATE_PREFERENCE('my_wordlist', 'BASIC_WORDLIST');
CTX_DDL.SET_ATTRIBUTE('my_wordlist', 'SUBSTRING_INDEX', 'YES');
CTX_DDL.SET_ATTRIBUTE('my_wordlist', 'PREFIX_INDEX', 'YES');
END;
/
-- 위 설정들을 적용하여 인덱스 생성
CREATE INDEX idx_tb_name_text ON tb_name(name)
INDEXTYPE IS CTXSYS.CONTEXT
PARAMETERS ('LEXER my_lexer WORDLIST my_wordlist SYNC (ON COMMIT)');
역 인덱싱 도입 시 성능 변화 (예상)
- Full Scan (기존): 5천만 건 전체 블록 I/O 발생 → **수십 초~분 단위**
- Inverted Index (개선): 인덱스에서 키워드 탐색 후 해당 Row만 Fetch → **0.x초~수 초 이내**
직접 구현하는 방식 (작동방식 원리 이해를 위해)
- 만약 Oracle Text라는 기능을 쓰지 않고 SQL/테이블 구조로만 역 인덱싱을 흉내 내려면 다음과 같은 설계가 필요합니다 (권장하지는 않지만 이론적으로 가능합니다).
- 맵핑 테이블 생성: `(word VARCHAR2(100), target_rowid ROWID)` 구조의 테이블 생성.
- 데이터 분해: `name` 컬럼의 데이터를 공백이나 특정 단위로 쪼개서 맵핑 테이블에 `INSERT`.
- 조회: 맵핑 테이블에서 `word = 'test'`로 조회하여 원본 테이블과 `JOIN`.
> **현실적인 조언:** 5천만 건의 데이터를 직접 SQL로 쪼개서 관리하는 것은 동기화와 저장 공간 문제로 매우 어렵습니다. 오라클이 공식 지원하는 **Oracle Text**를 사용하시는 것이 가장 안정적인 역 인덱싱 구현 방법입니다.
- 역 인덱싱(Oracle Text)을 적용하기 위해 **현재 운영 환경의 Tablespace 여유 공간**이나 **DML(입력/수정) 발생 빈도**를 체크해 보시는 것이 좋습니다.