안녕하세요
제목이 없는 게시판 형태의 DB 설계를 하려고 합니다
USER(InnoDB)
SEQ| EMAIL | NICKNAME | IS_DEL | REG_TIME
PK(SEQ)
UK(EMAIL), UK(NICKNAME)
POST(InnoDB)
SEQ | USER_SEQ | CONTENT | CATEGORY | LIKE_COUNT | COMMENT_COUNT | IS_DEL | REG_TIME
PK(SEQ,)
INDEX(USER_SEQ)
COMMENT(InnoDB)
SEQ | POST_SEQ | USER_SEQ | CONTENT | LIKE_COUNT | IS_DEL | REG_TIME
PK(SEQ)
INDEX(POST_SEQ,)
INDEX(USER_SEQ)
위와 같은 테이블을 만들려고하고 있고 백엔드에서 사용되는 쿼리는
1. 게시글(POST)를 최신순으로 5개씩 출력
2. 특정 POST_SEQ에 대한 댓글(COMMENT) 리스트를 출력
이렇게 2가지라고 생각하고 있습니다.
QUERY
1. 게시글(POST)를 최신순으로 5개씩 출력
SELECT P.SEQ ,P.CONTENT ,P.CATEGORY ,P.LIKE_COUNT ,P.COMMENT_COUNT ,P.REG_TIME, ,U.EMAIL ,U.NICKNAME FROM( SELECT SEQ FROM POST WHERE SEQ < ? AND IS_DEL = FALSE ORDER BY SEQ DESC LIMIT 5 ) A INNER JOIN POST P ON A.SEQ = P.SEQ INNER JOIN USER U ON P.USER_SEQ = U.SEQ;
2. 특정 POST_SEQ에 대한 댓글(COMMENT) 리스트를 출력
SELECT C.SEQ ,C.CONTENT ,C.LIKE_COUNT ,C.REG_TIME ,U.NICKNAME FROM( SELECT SEQ FROM COMMENT WHERE POST_SEQ = ? AND IS_DEL = FALSE ) A INNER JOIN COMMENT C ON A.SEQ = C.SEQ INNER JOIN USER U ON C.USER_SEQ = U.SEQ;
QUESTION
SELECT SEQ FROM POST WHERE SEQ < ? AND IS_DEL = FALSE
SELECT SEQ FROM COMMENT WHERE POST_SEQ = ? AND IS_DEL = FALSE
이 부분때문에 커버링 인덱스가 되질 않을 것 같습니다(맞을까요?)
하지만 인라인뷰를 쓰지않으면 IS_DEL = FALSE인 모든 POST 레코드 또는 모든 COMMENT와 USER가 조인될 것 같아서요..
쿼리 개선 또는 테이블 구조를 개선할 점이 있을까요?ㅠㅠ
MySQL의 서브쿼리는 생각처럼 동작하지 않을 때가 많은데.. 지금 본문에서도 인라인뷰는 성능을 깎아먹는 요소입니다.
EXPLAIN 결과를 보시면 아시겠지만.. 생각하시는 것처럼 동작하지 않습니다.
아래와 같이 인라인 뷰를 모두 제거하시길 권해 드립니다.
1번
SELECT STRAIGHT_JOIN P.SEQ ,P.CONTENT ,P.CATEGORY ,P.LIKE_COUNT ,P.COMMENT_COUNT ,P.REG_TIME ,U.EMAIL ,U.NICKNAME FROM POST P FORCE INDEX FOR JOIN (PRIMARY) INNER JOIN USER U FORCE INDEX FOR JOIN (PRIMARY) ON P.USER_SEQ = U.SEQ WHERE P.SEQ < ? AND P.IS_DEL = FALSE ORDER BY P.SEQ DESC LIMIT 5;
위 쿼리에서 P.SEQ < ? AND P.IS_DEL = FALSE 는 인덱스 커버링이 필요하지 않은게.. 이미 P.SEQ가 PK이고 클러스터드라서 LOOK-UP 없이 빠르게 수행됩니다.
2번
SELECT STRAIGHT_JOIN C.SEQ ,C.CONTENT ,C.LIKE_COUNT ,C.REG_TIME ,U.NICKNAME FROM COMMENT C FORCE INDEX FOR JOIN (POST_SEQ에 걸린 인덱스) INNER JOIN USER U FORCE INDEX FOR JOIN (PRIMARY) ON C.USER_SEQ = U.SEQ WHERE C.POST_SEQ = ? AND C.IS_DEL = FALSE;
여기서는 인덱스 커버링이 되지 않기 때문에, COMMENT 테이블에 "POST_SEQ, IS_DEL" 의 순서로 복합 인덱스를 생성하고.. 기존에 POST_SEQ 단일 컬럼에 걸린 인덱스를 삭제하는 것이 좋겠습니다.