MYSQL 현업 실수 모음집
지난해 하반기부터 실무에서 직적 SQL 쿼리를 돌리면서 데이터 추출과 분석을 하고 있다. 고객에 대한 인사이트뿐만이 아니라 개발 구조에 대해서도 구체적으로 이해할 수 있는 기회가 되어서 너무 만족하고 있다.
무엇보다 나의 비루한 쿼리를 보고 같이 고민해주고 도움을 주시는 데이터팀에게 무한한 감사를 느끼면서 이번 SQL 복습 게시글을 작성하는중이다. 나와 같이 SQL을 실무에서 사용하기 시작한 사람들이 보면 충분히 공감할 수 있을 만한 내용이 될것같다.
실무에서 가장 많은 실수가 일어나는 부분은 테이블과 데이터에 대한 이해이다. 어떻게 쌓여진 데이터인지? 어떤 목적을 하는 데이터인지? 그리고 어떤 케이스로 활용되어 왔는지? 를 알고 접근한다면 더 효율적으로 테이블을 활용할 수 있다. 이러한 이해가 없는 상태에서 내가 했던 대표적인 실수는 아래와 같다.
중복되는 데이터인가? Unique한 데이터인가?
join을 하는 과정에서 join 테이블의 연결 key값이 복수인 경우에 중복 조인의 문제가 발생할 수 있다.
그래서 생소한 테이블의 경우에는 join 작업을 할때는 반드시 각 연결 key 값이 unique한지를 확인해야 한다. 이를 쉽게 해결할 수 있는 방법 중 하나는 서브쿼리에서 해당 Key를 DISTINCT를 활용해서 Unique하게 만다는것이다.
1. 회원테이블의 Key 데이터가 복수인 경우
- 가입과 탈퇴를 반복하여 해당 UID로 여러 개의 기록
- 가장 최근의 탈퇴 기록이 없는 회원 데이터만 가져와야 한다.
SELECT DISTINCT UID
또한, 중복조인으로 인해 지나치게 많은 데이터의 조회나 연산을 하게 되면 성능이 안좋아져서 쿼리를 실행하는데 긴 시간이 소요되거나 아예 timeout으로 실행이 안되기도 한다.
2. null이 포함되어 있는가?
연산을 하는 데이터에 null이 포함되어 있다면, 연산시에 결과값으로 null이 나오기 때문에 null이 포함되어 있지는 않은지 확인하고 null인 경우 '0'으로 반환하는 등의 대응을 할 수 있다.
ex) 평균을 구하려고 했을때 C 데이터에는 null이 있다면 A + B +C(null) = null이 됨
(sum("3m_ago")+sum("2m_ago")+sum("1m_ago"))/3 as "M-3 ~ M-1 3개월간의 평균 거래량"
잘못된 조건을 설정한 경우
가령, 고객의 주문 행태를 알기 위해서 구매 데이터를 뽑으려고 할때 buy라는 값을 where 조건에서 제한했다고 하였다고 가정해보자. 그런데 알고보니 buy라는 유형에는 구매가 완료된 데이터와 구매가 취소된 데이터가 포함되어 있다면, 내 의도와 다른 데이터가 추출된다.
그럴때는 주문이 취소되지 않은 조건을 추가로 설정하여서 추출을 해야 한다. 이 역시 SQL 문법에 대한 이해보다는 내가 접근하고자 하는 테이블과 데이터에 대한 파악이 선행되지 않았기 때문이다.
WHERE tx_type = 'buy'
and is_cancle = 'N'
서브쿼리의 가독성을 위해서 쿼리 초반에 먼저 정의
서브쿼리는 from절 안에 작성하다보니 쿼리가 길어지기 부지기수이다. 그래서 가독성을 위해서 초반에 with 절로 테이블을 정의하였더니, 나의 쿼리를 보고 쉽게 이해하였다는 피드백을 주는 동료들이 많아졌다.
아래와 같이 서브쿼리를 raw_data로 선정의하고 본 쿼리에서는 from으로 불러오기만 하였다.
with raw_data as (
SELECT *
FROM TABLE_01
LEFT JOIN TABLE_02
WHERE tx_type = 'buy'
) -- 서브쿼리 테이블
SELECT *
FROM raw_data
WHERE tx_type = 'buy'
서버에서 설정한 시간에 따라서 시간 변환이 필요한 경우가 있다. UTC를 기준으로 서버의 시간이 설정되어 있다면 한국 시간과 9시간이 차이나게 되어, 내가 의도한 시간대의 데이터를 뽑지 못하게 된다.
그럴때는 convert_timezone 함수를 사용해서 시간대를 변환할 수 있다.
convert_timezone('kst',registered_at)
매출이나 회원 데이터와 같이 데이터가 무수히 많은 테이블을 조회하다보면, 성능 이슈가 발생한다. 단순한 조회의 용도라면 성능에 대해서 크게 신경쓰지 않아도 되지만, 조회 시간이 10초가 넘어가면 이런 저런 작업을 하는데도 방해물이 되었다.
아래와 같이 나의 분석 목적에 알맞게 적적히 조건절을 사용하면 성능을 향상시킬 수 있다.
WHERE tx_type = 'buy'
AND is_cancle = 'N'
AND BETWEEN order_date '2024-01-01' and '2024-01-31'
이외의 SQL 함수는 그때그때 공부하면서 사용하면 되기 때문에 크게 문제가 되지는 않았다. 특히 CHAT GPT로 쿼리의 성능을 개선하거나 모르는 함수를 질문할때 가장 활용도가 좋았다. 동료들의 말로는 초반에 우리 테이블의 구조에 대해서 CHAT GPT에 학습시키는 과정이 까다롭지만, 한번 길들이면 이후엔 사용하기 편리하다고 한다.
아직은 미숙한 탓에 쿼리를 작성하는 공부를 위주로 했던것같은데 앞으로는 SQL의 잔실수를 줄이고, 데이터의 추출보다는 나의 분석 의도와 결과를 검증하는 과정에 집중하고 싶다.