노트
- 셀프 조인은 언제 써야할까? 대표적인 3가지 상황 예시를 다음과 같이 들어본다
- 특정 Column 이 자신 테이블의 PK 인 경우 (1) - 게시글 댓글의 답글 (계층 구조)
comments(댓글)
라는 테이블이 있다. 댓글에 대해 답글을 다는 기능을 넣는다고 생각해보자.- 자신의 부모 댓글을 지정하는 칼럼인 parent_comment_id에 해당하는 comment_id 가 들어가게 된다.
- 이 때 댓글을 불러올때 각 댓글의 답글 리스트를 붙여서 불러오고 싶다고 생각해보자.
- 다음과 같이 Self Join을 수행해야 할 것이다.
id(PK) | parent_comment_id(FK) | comment |
1 | NULL | hello |
2 | 1 | hi |
SELECT * FROM comments c JOIN comments sub ON c.id = sub.parend_comment_id WHERE c.parent_comment_id is not null
couple(커플)
이라는 테이블이 있다. 자신의 연인 정보(lover_id)도 함께 들어가는 테이블이다.- lover_id 는 자신의 연인의 ID 값이며, 동일한 테이블에 다른 row로 존재한다.
- 이 때 각 커플들의 두 사람 모두의 정보를 가져와야 하는 경우(남자의 이름, 여자의 이름)를 생각해보자.
- 이때 lover(상대방)의 name도 가져오고 싶다? 그러기 위해 Self join 을 사용할 수 있다.
id(PK) | name | lover_id(FK) |
1 | a | 2 |
2 | b | 1 |
3 | c | 4 |
4 | d | 3 |
5 | e | 6 |
SELECT me.name, lv.name from couple me JOIN couple lv ON me.id = lv.lover_id
- 예를 들어,
뉴스 피드(feed)
라는 테이블이 있다. PK는 UUID 라고 가정해보자. - 여기서, 최신순으로(createdAt의 내림차순) 피드를 가져오는 쿼리를 작성할 것이고 테이블은 다음과 같다.
- 그런데 페이지네이션을 고려해서 어떤 특정 뉴스 ID가 주어졌을 때 해당 뉴스 ID 이전에 생성된 뉴스들을 가져오는 쿼리를 작성한다고 생각해보자. (다만, 성능을 고려해, 커서 기반으로 할 것이다, created_at은 인덱스가 걸려있다 가정하면)
- 그런데 ID가 Auto Increment 또는 특정 순서로 정렬되어 있지 않다면? 그냥 SELECT 쿼리와 WHERE Range 쿼리를 쓸 수 없다. 따라서
- 서브쿼리를 작성하거나
- 조인을 수행해야한다.
- 이 때 조인을 만약 수행한다면, 당연히 자기 자신 테이블을 수행해야 한다.
- 물론, 그냥 LIMIT OFFSET 과 WHERE 을 쓰거나 Auto Increment 를 쓰면 되는거 아니냐? 일수도 있지만, 그렇게 할 수 없는 경우도 있다.
- created_at을 cursor 키로 쓰면 되는거 아니냐? 라는 의문이 들 수 있지만, created_at은 UNIQUE 값이 아닌 특성이 있다는 걸 고려해보자.
- 참고로 이는 어떻게든 커버링 인덱스 조건을 만족하도록 하려는 성능적 특성을 고려하는 쿼리라고 볼 수 있다.
id(PK) | created_at | title |
? | 2023-09-09 | a |
? | 2023-09-07 | b |
요약
요약: 테이블내 데이터가 계층적이거나, 자신을 참조해서 결과를 보여줘야 하거나, 커버링 인덱스를 만족시키기 위한 쿼리를 만드는 일부 경우.