데이터베이스 LIKE문 제대로 이해하고 사용하기
데이터베이스 검색 쿼리를 작성하다 보면 텍스트 일치 확인이 필요한 순간이 자주 찾아옵니다. 키워드 자동완성 기능을 구현하거나, 사용자가 작성한 글에서 특정 키워드가 포함되어 있는지 확인하는 등 다양한 상황에서 LIKE 문을 사용하게 됩니다.
하지만 LIKE 문을 잘못 사용하면 전체 데이터를 스캔하는 Full Table Scan이 발생하여 심각한 성능 이슈로 이어질 수 있습니다.
LIKE 문의 성능 문제
LIKE 문은 패턴 매칭을 통해 텍스트를 검색하는 강력한 기능이지만, 와일드카드(%)의 위치에 따라 성능이 천차만별로 달라집니다.
인덱스를 활용할 수 없는 경우
검색어의 앞이나 양쪽에 %를 사용하면, 인덱스를 생성해두었더라도 데이터베이스는 인덱스를 활용하지 못하고 전체 테이블을 스캔하게 됩니다.
-- 나쁜 예시
SELECT * FROM member WHERE username LIKE '%mike%';
SELECT * FROM member WHERE username LIKE '%mike';
인덱스는 데이터가 정렬된 상태로 저장되어 있습니다. 하지만 검색어 앞에 %가 붙으면 어떤 문자로 시작하는지 알 수 없기 때문에 인덱스의 정렬 순서를 활용할 수 없게 됩니다.
인덱스를 활용할 수 있는 경우 반면 검색어 뒤에만 %를 사용하면 인덱스를 효과적으로 활용할 수 있습니다.
-- 좋은 예시
SELECT * FROM member WHERE username LIKE 'mike%';
이 경우 ‘mike’로 시작하는 모든 데이터를 찾는 것이므로, 인덱스의 정렬 순서를 따라 빠르게 검색할 수 있습니다.
최적화 방법
1. 인덱스 추가
LIKE문을 사용하는 컬럼에는 반드시 인덱스를 추가해야 합니다.
CREATE INDEX idx_username ON member(username);
2. 와일드카드 위치 조정
검색 요구사항을 분석하여 가능하다면 접두사 검색형태로 변경합니다.
- 접두사 검색: ‘mike%’ – 인덱스 활용 가능
- 중간 검색: ‘%mike%’ – 인덱스 활용 불가
- 접미사 검색: ‘%mike’ – 인덱스 활용 불가 3. 성능 차이 체감하기
실제로 100만 건의 데이터가 있는 테이블에서 테스트해보면:
- username LIKE ‘mike%’ (인덱스 활용): 0.01초
- username LIKE ‘%mike%’ (Full Scan): 2.5초
3. Full-Text Search 활용하기
만약 중간 검색이나 접미사 검색이 필수적이라면 Full-Text Search를 고려할 수 있습니다.
Full-Text Search란?
Full-Text Search는 일반 B-Tree 인덱스와는 다른 전용 FULLTEXT 인덱스를 사용하는 검색 방식입니다. 역색인(Inverted Index) 구조를 통해 텍스트를 단어 단위로 분해하고, 각 단어가 어느 문서에 나타나는지 매핑합니다.
-- FULLTEXT 인덱스 생성
CREATE FULLTEXT INDEX idx_content ON articles(content);
-- 일반 LIKE (인덱스 활용 불가)
SELECT * FROM articles WHERE content LIKE '%데이터베이스%';
-- FULLTEXT 검색 (FULLTEXT 인덱스 활용)
SELECT * FROM articles WHERE MATCH(content) AGAINST('데이터베이스' IN NATURAL LANGUAGE MODE);
Full-Text Search의 장점
- 중간 검색(
%keyword%) 패턴도 효율적으로 처리 - 관련도(relevance) 기반 정렬 가능
- 불용어(stopwords) 처리 자동화
Full-Text Search의 성능 이슈
1. 인덱스 크기 문제
FULLTEXT 인덱스는 텍스트 데이터를 단어 단위로 분해하여 저장하기 때문에 원본 테이블 크기의 50~100%까지 인덱스 크기가 증가할 수 있습니다. 이는 디스크 공간 소모와 메모리 부족으로 이어질 수 있습니다.
2. INSERT/UPDATE 성능 저하
새로운 데이터를 추가하거나 수정할 때마다 텍스트를 단어로 분해하고 역색인을 업데이트해야 하므로 일반 인덱스보다 쓰기 작업이 느립니다. 쓰기 작업이 많은 시스템에서는 병목 현상이 발생할 수 있습니다.
3. 복잡한 검색 쿼리
SELECT * FROM articles
WHERE MATCH(content) AGAINST('+데이터베이스 +최적화 -느림' IN BOOLEAN MODE)
AND created_at > '2024–01–01'
ORDER BY relevance DESC
LIMIT 1000;
여러 조건을 조합하거나 매칭되는 문서가 수만~수십만 건인 경우 여전히 성능 저하가 발생할 수 있습니다.
4. 한글 처리 문제
기본 Full-Text Search는 영어에 최적화되어 있습니다. 한글을 제대로 처리하려면 ngram 파서를 사용해야 합니다.
CREATE FULLTEXT INDEX idx_content ON articles(content) WITH PARSER ngram;
마무리
LIKE 문은 간단하고 직관적이지만, 잘못 사용하면 서비스 전체의 성능에 악영향을 미칠 수 있습니다.
핵심 원칙을 정리하면 검색 컬럼에 인덱스를 생성하고 와일드카드는 검색어 뒤에만 사용하세요. 중간 검색이 필수라면 데이터 규모와 쓰기 빈도를 고려하여 Full-Text Search나 전문 검색 엔진을 선택하세요
Enjoy Reading This Article?
Here are some more articles you might like to read next: