게시판 검색이 느리다는 이야기를 들었다. 목록은 바로 뜨는데 검색만 삼 초쯤 걸린다고 했다. 인덱스가 없나 싶어 SHOW INDEX 로 확인했더니 검색하는 컬럼에 정확히 걸려 있었다.
Table of contents
Open Table of contents
인덱스가 있는데 안 썼다
EXPLAIN 을 보니 key 가 NULL 이고 type 이 ALL 이었다. 인덱스를 안 쓰고 전체를 훑고 있었다. 걸려 있다는 것과 쓴다는 것은 다른 사실이었다. 쿼리 모양이 인덱스를 쓸 수 있는 형태가 아니면 걸려 있어도 소용이 없다.
검색 조건이 LIKE 에 앞뒤 양쪽으로 % 를 붙인 모양이었다. 인덱스는 앞에서부터 정렬돼 있어서 앞이 열리면 어디부터 찾을지 정할 수 없다. 사전에서 중간 글자로 단어를 찾는 것과 같은 상황이었다.
왜 지금까지 괜찮았나
같은 코드가 배포된 것은 한참 전인데 느려진 것은 최근이었다. 전체를 훑는 비용은 행 수에 비례해서 늘어난다. 행이 적을 때는 훑어도 빨라서 아무도 몰랐다.
느려지는 시점은 배포한 날이 아니라 자료가 쌓인 날이었다. EXPLAIN 의 rows 를 미리 봤으면 짐작할 수 있었다. 그 값은 추정치라 실제 건수도 따로 세어 봐야 한다. 지금 빠른 것이 앞으로도 빠르다는 뜻은 아니었다.
범위를 먼저 좁혀 되살렸다
앞의 % 를 뗄 수 있는 조건인지 먼저 봤는데 게시판 검색은 그럴 수 없었다. 그래서 다른 조건으로 범위를 먼저 좁히는 쪽을 택했다. 게시판 번호와 기간으로 좁히고 그 안에서만 부분 일치를 걸었다.
좁혀진 범위가 작으니 훑어도 빨랐다. FULLTEXT 를 쓰는 방법도 있었지만 이번 규모에서는 필요하지 않았다. 범위를 좁히는 조건이 화면에 이미 있었다는 것이 다행이었다.
이어 붙인 컬럼
조사하다 한 컬럼에 값 여러 개를 구분자로 이어 붙여 둔 자리를 발견했다. 그 컬럼에서 특정 값을 찾으려면 부분 일치를 쓸 수밖에 없다. 그러면 그 값으로는 영원히 인덱스를 못 쓴다.
그 자리는 별도 테이블로 나눠야 했다. 지금 당장은 건수가 적어 빠르지만 같은 이유로 언젠가 느려진다. 고친 뒤에는 EXPLAIN 을 다시 봐서 type 이 ALL 에서 벗어났는지 확인했다.
정리
- 인덱스가 걸려 있는 것과 쓰는 것은 다르다
- 앞에
%가 붙은LIKE는 인덱스를 못 쓴다 - 사전에서 중간 글자로 찾는 것과 같다
- 느려지는 시점은 배포한 날이 아니라 자료가 쌓인 날이다
EXPLAIN의rows를 미리 본다. 추정치라 실제 건수도 센다- 다른 조건으로 범위를 먼저 좁힌다
- 한 컬럼에 값을 이어 붙이면 그 값으로 인덱스를 못 쓴다
- 고친 뒤
EXPLAIN을 다시 본다