FULLTEXT 인덱스
- 게시글 제목 검색 등의 기능을 위한 쿼리는 다음과 같다.
SELECT id, category, writerId, title, content FROM article WHERE title like '%검색어%' order by id DESC limit 10- 허나 이러한 like 조건은 풀스캔을 유발한다.
- (이를 사용하지 않기 위해) 엘라스틱 서치 와 같은 검색엔진을 사용하면 DB 를 사용하지 않고 검색 기능을 구현할 수 있다.
- (만약 이와 같은 도구를 사용하는 것이 힘들다면) DB 가 제공하는 FULLTEXT 검색 기능을 활용하자.
FULLTEXT 인덱스를 고려하면 풀스캔 없이 문자열 검색 쿼리를 실행할 수 있다
커버링 인덱스를 활용해라
커버링 인덱스는 특정 쿼리를 실행하는데 필요한 모든 쿼리를 포함하는 인덱스를 뜻한다.
실제 데이터를 읽어오는 과정이 생략되므로 쿼리 실행 시간이 빨라진다.
과다 사용은 금물 아래글을 보라.
만약 id 가 AI라면 offset 기준으로 조회하는 것이 아닌 ID 기준으로 조회하는 것이 좋다.
select id, subject, writer, regdt
from article
order by id desc
limit 10 offset 99990;
만약 위와 같은 쿼리가 있다면 DB 는 99,991 부터 10개 세면 좋겠지만 어떤 값이 99,990인지 모르므로 데이터를 세는 시간만큼 실행 시간이 증가한다.
그러므로 특정 ID 를 기준으로 조회하면 좋다.
꿀팁
만약 프론트 개발자가 다음에 읽어올 데이터가 존재하는지 알려주는 속성을 응답 결과에 포함시켜 달라고 요청한다면 1개만 더 읽어 판단하면 된다.
예를 들어 10개를 조회하는 페이징이 있으면 11개를 조회하고 만약 조회한 데이터가 11개이면 다음에 읽을 데이터가 존재하므로 추가 데이터 존재 여부를 true 로 응답하면 된다.
JPA 의 pagenation 도 그렇게 동작하나? NO
🧩 책에서 제안한 방식
- 1페이지에 10개씩 조회
- 실제 쿼리:
limit 11 offset 0- 결과가 11개면 → 다음 페이지 존재 (
hasNext = true)- 결과가 10개 미만이면 → 마지막 페이지
➡ 장점: count 쿼리를 안 쳐서 빠름
➡ 단점: 전체 개수를 알 수 없음(total count 불명)
🧩 JPA의 기본 방식
- 1페이지에 10개씩 조회
- 실제 쿼리:
limit 10 offset 0- 별도로
select count(*)실행- count 결과와 현재 offset으로 다음 페이지 존재 여부 계산
➡ 장점: 전체 페이지 수(total count) 를 알 수 있음
➡ 단점: count 쿼리 비용이 큼 (특히 큰 테이블에서)
⚙️ 3. 정리
구분 방식 장점 단점 JPA 기본 Page limit + count(*) 전체 개수, 페이지 수 알 수 있음 count 쿼리 부담 limit+1 방식 (프론트 제안) limit + 1 빠름, 단순함 전체 개수 불명
💡 4. 실무 팁
성능 이슈로
count(*)쿼리를 피하고 싶다면
Slice<T>를 사용하는 방법이 있습니다.Slice<Post> posts = postRepository.findAllByOrderByCreatedAtDesc(PageRequest.of(0, 10));➡
Slice는 count 쿼리를 날리지 않고,내부적으로 limit+1 방식으로 다음 페이지 존재 여부(
hasNext())를 판단합니다.
APM 프로그램 항상 쉽게 볼 수 있는 곳에 띄워두기
- 서비스를 진행할 경우 서비스가 정상일 때 으답시간 분포가 어떤 형태를 띠는지 감을 잡을 수 있다.
단편화, 최적화
- DELETE 쿼리를 사용해도 실제 사용하는 디스크 양은 같다.
- 하지만 데이터가 반복적으로 추가되고 변경되고 삭제되는 과정에서 데이터가 흩어져 저장되ㅗㄱ 빈 공간이 생기는 단편화 현상이 발생할 수 있다.
- 이를 방지하기 위해 최적화 작업을 한다.
- 질문답변.
질문 1.
서적에서 추가 데이터 페이징 처리를 구현할때에라고 했는데 JPA 의 pagenatnion 또한 count 쿼리를 활용하지 않고 동일하게 동작할까요?만약 프론트 개발자가 다음에 읽어올 데이터가 존재하는지 알려주는 속성을 응답 결과에 포함시켜 달라고 요청한다면 1개만 더 읽어 판단하면 된다. 예를 들어 10개를 조회하는 페이징이 있으면 11개를 조회하고 만약 조회한 데이터가 11개이면 다음에 읽을 데이터가 존재하므로 추가 데이터 존재 여부를 true 로 응답하면 된다.질문 2
테이블 단편화를 해결하기 위해OPTIMIZE TABLE명령어(서적에서 언급한 최적화)를 사용할 수 있다고 알고 있습니다.
하지만 운영 중인 서비스의 테이블에 이 명령어를 바로 실행하기 어려운 이유는 무엇이며, 어떤 대안을 고려할 수 있을까요?힌트 : 서적에서 DML 을 운영중인 테이블에 사용하면 안된다고 한 이유와 같다.