Backend 개발자/StackOverflow

Mssql DISTINCT 대신 서브쿼리 EXISTS 사용하기

by 앵과장 2022. 12. 6. 15:52
반응형

언제가 부터 RDBMS로 다양한 관계를 복잡하게 Query로 구현하기보다는 

개발자 관점에서 테이블설계를 하고 필요하다면 CQRS패턴을 이용하고 in memory 다양한 방법으로 복잡도높은 테이블 구조를 만들지 않고 있었는데 어쩔수 없는 상황에 관계형 데이터베이스 테이블을 구현하면서 배워온것들을 정리해볼까 합니다.

 

JOIN 종류

 

https://aquerytool.com/

 

AQueryTool

{{source.erd_info.erd_name + '(Ver ' + erdVersion + ', ' + source.erd_info.db_type + ')'}}

aquerytool.com

ERD SASS기반

USER 테이블

userId name email
1 renzo renzo@gmail.com
2 guest guest@gmail.com
3 yuna yuna@gmail.com

CODE 테이블

id userId regDate code
1 1 2023-01-01 001
2 1 2023-01-02 002
3 2 2023-01-01 001
4 3 2023-01-04 003

 

USER, CODE 테이블 2개가 있다고 가정하고 

 

One To Many
SELECT T3.* FROM
    (SELECT
        T1.userId,
        T1.name,
        T1.email,
        T2.id,
        T2.regDate,
        T2.code
    FROM
        USER T1,
        USER T2
    WHERE T1.userId = T2.USER_Id) T3
WHERE T3.userId = 1;

위에처럼 가져올수도 있지만 되도록이면 Join되는 형태가 어떻게 관계되는지 아래처럼 작업하는것을 코드리뷰하면 코멘트로 볼수 있는데 코드리뷰 해주는사람이 없으면 나처럼 5년동안 위에처럼 하는경우가 발생할수 있으니 참고하세요!!

SELECT T3.* FROM
    (SELECT 
        T1.userId,
        T1.name,
        T1.email,
        T2.id,
        T2.regDate,
        T2.code
    FROM 
    USER T1 LEFT JOIN CODE T2 ON T1.userId = T2.userId) T3
WHERE T3.userId = 1;

 

Many to One 데이터 조회시 Many 기준으로 가져올때 중복되는 데이터 없에는 방법

CODE 테이블에 code 값이 001,002 포함하고 있는 User 정보만 노출하고 싶다면 어떻게 해야되지?

SELECT 
    T3.userId,
    T3.name,
    T3.email 
FROM
    (SELECT
        T1.userId,
        T1.name,
        T1.email,
        T2.CODE
    FROM
    USER T1LEFT JOIN CODE T2 ON T1.userId = T2.userId) T3
WHERE T3.CODE IN ('001','002')

이렇게하면 아래처럼 데이터가 나오는데 userId가 중복되어 나온다. 

id userId regDate
1 1 2023-01-01
2 1 2023-01-02
3 2 2023-01-01

중복은 제거하고 싶다면 

DISTINCT를 사용하면된다.

SELECT
    DISTINCT
    T3.userId,
    T3.name,
    T3.email
FROM
    (SELECT
        T1.userId,
        T1.name,
        T1.email,
        T2.CODE
    FROM
    USER T1 LEFT JOIN CODE T2 ON T1.userId = T2.userId) T3
WHERE T3.CODE IN ('001','002')

하지만 IN절에 code가 많아진다면 성능상 이슈도 있고 하다보면 다른 여러문제가 발생할수 있어서 분리를 할수 있다면 분리하는 방법이 있는데 이때 사용하는게 EXISTS 기능

 

CODE 테이블에 001,002 코드의 정보가 존재하는지에 대한 체크를 해서 전달하기 때문에 위에 Query보다 성능이 좋다.

SELECT
    T1.userId,
    T1.name,
    T1.email
FROM USER T1
WHERE EXISTS (
    SELECT 1 FROM CODE T2 WHERE T1.userId = T2.userId
    AND T2.code IN ('001','002')
)

중복되는 유저정보도 날릴수 있고 LEFT JOIN 도 없에버릴수 있고 코드의 양도 줄어들게된다.

id userId regDate
1 1 2023-01-01
3 2 2023-01-01