[Spring] Full-Text Index를 활용한 DB 검색 성능 최적화 (1) 도입배경, MySQL Full-Text Index 생성

도입배경

  • JPA를 이용해 검색 기능을 구현했지만, 대량의 레코드에서 검색 시간이 오래걸리는 문제가 발생하였습니다.
  • Native Query와 Full Text Index를 활용하여 검색 성능을 개선할 수 있다는것을 알게되습니다.
  • 직접 코드를 구현하여 성능일 비교하고, 프로젝트에 적용해보았습니다.

Full Text Index를 사용하는 이유

  • Full Text Index는 텍스트 기반 데이터의 검색 속도를 높이기 위한 인덱스 방식입니다.
  • 특히 긴 문자열에서 특정 단어를 빠르게 찾기 위해 사용되며, 검색 대상이 되는 데이터가 크고 복잡할수록 성능 향상이 두드러집니다.
  • 한국어는 영어와 달리 단어별로 명확한 띄어쓰기가 없어 검색 성능 향상이 쉽지 않지만, MySQL의 n-gram parser를 이용해 이를 보완할 수 있습니다.
  • n-gram parser는 문자열을 일정 길이(기본값: 2글자)로 분할하여 토큰으로 저장해 인덱스를 생성하며, 이로 인해 긴 텍스트에서도 원하는 단어를 빠르게 찾을 수 있습니다.

MySQL에서 Full Text Index 생성하기

1. 생성 SQL 문

  • Full Text Index는 일반적인 인덱스와 유사하게 SQL로 생성할 수 있으며, WITH PARSER ngram 구문을 통해 n-gram parser로 인덱스를 생성할 수 있습니다.

  • 아래 예시는 소설의 제목을 대상으로 Full Text Index를 생성하는 코드입니다.

    CREATE FULLTEXT INDEX ft_index_title_description 
    ON novel (title)
    WITH PARSER ngram;

2. 인덱스 조회 SQL 문

  • 생성된 인덱스가 실제로 적용되는지 확인하기 위해 두 가지 방법을 사용할 수 있습니다.

1) EXPLAIN 명령어

  • EXPLAIN 명령어로 실행 계획을 확인하여, 생성한 INDEX가 실제로 적용되는지 검증 할 수 있습니다.
  • 결과적으로 SELECT 문 실행 시 생성한 Full Text Index가 정상적으로 적용되는 것을 확인할 수 있었습니다.
EXPLAIN SELECT * 
FROM novel 
WHERE MATCH(title) AGAINST('검색어');

etc-image-0

2) 시스템 변수 이용

  • MySQL에서는 innodb_ft_aux_table 시스템 변수를 사용해 특정 테이블의 Full Text Index 정보를 자세히 확인할 수 있습니다.
  • information_schema.INNODB_FT_INDEX_TABLE 테이블을 통해 인덱스에 포함된 토큰과 각 토큰이 몇 개의 레코드에 등장하는지 조회할 수 있습니다.
  • 이 설정은 글로벌 변수이므로 테스트 시에만 활성화해야 합니다.
SET GLOBAL innodb_ft_aux_table = 'netnovel/novel';
SELECT * 
FROM information_schema.INNODB_FT_INDEX_TABLE;

etc-image-1

결론

  • 이번 포스트에서는 대용량 텍스트 데이터를 효과적으로 검색하기 위해 MySQL에서 Full Text Index를 사용하는 이유와 생성 및 검증 방법을 다루었습니다.
  • 다음 포스트에서는 이 인덱스를 활용하여 JPA와 Native Query로 조회하는 방법과 그 성능을 비교해 보겠습니다.