Django mysql Full Text Index 먹이기

     

 

DB 테이블에 index작업을 해주는 것은 아주 중요하다.

 

각각의 트랜잭션이 얼마나 빠르게 실행되고, 결과를 리턴하는지에 따라 서버에 성능이나 부하, 프로덕트의 속도 등이 결정되기 때문이다. 같은 테이블인데도 index가 있고 없고에 따라 속도가 100배 이상 차이나는 서비스가 될 수도 있다. 

 

대부분 primary키에 index가 걸려있고, 검색을 자주하는 컬럼(where 절에 자주 들어가는)이 인덱스로 잡히게 된다.

 

최근에 문장에서 키워드를 검색하여 키워드가 포함된 row를 추출하는 서비스를 만들어야 하는 일이 생겼다. 이럴 때는 그냥 index를 쓰면 되는 것일까?

 

검색해보니 mysql에서 full text index를 지원한다는 것을 찾아냈다. full text index는 문장을 index화 하여 필요한 것과 필요 없는 단어들을 알아서 결정해서 구성해주는 아주 좋은 기능이다. 

 

Django에서도 역시 지원 가능하다. 

 

Django 공식 홈페이지 스팩

그렇다면 Django에 쿼리셋에서 FULLTEXT INDEX를 사용하는 조건은 어떻게 사용할까?

 

IssueList.objects.filter(question__search=keyword)

 

위와 같이 filter에 __search를 사용하면 FULLTEXT INDEX가 먹혀서 빠르게 검색이 된다.

테이블에 index를 먹이는 방법은 migrations.py에 넣어도 되고 DB에 직접 쿼리를 처도 된다.

 

migrations.RunSQL(
    sql='CREATE FULLTEXT INDEX `idx_description` on foo(`description`);',
    reverse_sql='ALTER TABLE foo DROP INDEX idx_description',
),

 

위 쿼리를 입력하면 끝.

키워드 검색이 필요한 DB 스키마를 짤 때 잘 써먹어보자.

 

 

----- 추가 정보 ------

 

원래는 단순 텍스트 검색을 위해 FULLTEXT INDEX를 사용하려고 했으나, 분명히 문장 안에 포함된 단어인데도 검색이 안 되는 현상이 발생했다. 아마도 FULLTEXT INDEX를 먹이면 mySql자체에서 자연어 처리를 통해 검색에 사용할 단어 LIST를 뽑아 INDEX로 지정하는 것 같다. 그래서 정말 존재하는 단어임에도 불구하고 검색이 안 되는 일이 발생한다. 

 

즉 정말 대용량에 데이터에 mySql이 생성한 단어 인덱스 셋을 믿고 FULLTEXT IDNEX를 먹이는거면 상관없는데, 단순히 문장 안에 단어가 있는지 없는지만 판단하여 결과를 원할 경우는 FULLTEXT INDEX는 소용없다.

 

결국 인덱스 버리고 like검색으로 할려고 했는데, 구글링 해보니 like검색보다는 instr을 추천한다고 나와있다. instr은 특정 문자가 대상 문자열에 포함되어 있을 경우 그 위치를 반환해주는 쿼리 함수이다. 사실 둘 다 INDEX를 안 타서 느리긴 한데 instr은 문장에 한번 나오면 바로 함수가 종료되기 때문에 쌩 like보다는 좋다고 생각하는 것 같다. 

 

ps. 사실 DB에 100만건 이상의 데이터가 있고 그걸 검색하는 게 아니라면 아무거나 상관없더라...

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형

댓글

Designed by JB FACTORY