📌문제
https://school.programmers.co.kr/learn/courses/30/lessons/164670
프로그래머스
SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
말 그대로 조건에 맞는 사용자 정보를 조회하는 쿼리를 짜면 된다.
그러나 조회 포맷팅 조건이 다소 까다로웠음
중고거래 플랫폼의 사용자 중에서 중고 거래 게시물을 3건 이상 등록한 사용자만 추려, 유저 ID, 닉네임, 전체 주소, 전화번호를 조회하라는 문제
이때, 전체 주소는 CITY, STREET_ADDRESS1, STREET_ADDRESS2을 공백으로 이어붙이고, 전화번호는 01012345678 형식을 010-1234-5678로 변환해야 한다. 결과는 USER_ID 기준 내림차순으로 정렬해야 한다.
두 개의 방법으로 문제를 풀었는데 문득 두 개 중에 뭐가 더 성능이 좋을까 혹은 비슷할까 궁금해서 공부해보다가 블로그에 남겨두고 싶어서 포스팅해본다. 포맷팅 방식은 조금만 찾아보면 나오니까, 각 쿼리 방식마다의 장/단점 비교해보고 어느 상황에 어느 풀이가 유리할지 분석해보는 식으로 작성하겠음
📌첫 번째 풀이
SELECT
USER_ID,
NICKNAME,
CONCAT(CITY, ' ', STREET_ADDRESS1, ' ', STREET_ADDRESS2) AS '전체주소',
CONCAT(
SUBSTRING(TLNO, 1, 3), '-',
SUBSTRING(TLNO, 4, 4), '-',
SUBSTRING(TLNO, 8, 4)
) AS '전화번호'
FROM USED_GOODS_BOARD B
JOIN USED_GOODS_USER U ON B.WRITER_ID = U.USER_ID
GROUP BY USER_ID
HAVING COUNT(BOARD_ID) >= 3
ORDER BY USER_ID DESC
;
먼저 JOIN을 통해 게시글 테이블과 유저 테이블을 묶고, GROUP BY를 통해 유저별 게시글 수를 계산한 후 3건 이상인 유저만 필터링하는 방식이다.
장/단점
- 장점
- JOIN을 통해 데이터를 한 번에 가져올 수 있고, JOIN 조건에 인덱스가 잘 잡혀 있다면 효율적이다.
- GROUP BY로 묶어 처리하기 때문에 확장성 있는 분석에는 더 유리하다.
- 단점
- USED_GOODS_BOARD와 USED_GOODS_USER를 먼저 JOIN 후 GROUP BY → 불필요한 JOIN 결과가 많아질 수 있다. (특히 게시글 수가 많다면 중간 결과셋이 커짐)
- GROUP BY로 인해 MySQL은 내부적으로 임시 테이블을 사용할 수 있고, 디스크 정렬이나 정렬 연산이 비용이 클 수 있다.
📌두 번째 풀이
SELECT
USER_ID,
NICKNAME,
CONCAT(CITY, ' ', STREET_ADDRESS1, ' ', STREET_ADDRESS2) AS '전체주소',
CONCAT(
SUBSTRING(TLNO, 1, 3), '-',
SUBSTRING(TLNO, 4, 4), '-',
SUBSTRING(TLNO, 8)
) AS '전화번호' -- 여기까진 똑같음
FROM USED_GOODS_USER
WHERE USER_ID IN (
SELECT WRITER_ID
FROM USED_GOODS_BOARD
GROUP BY WRITER_ID
HAVING COUNT(*) >= 3
)
ORDER BY USER_ID DESC
;
조회 결과를 포맷팅하는 방식은 똑같은데 조건 필터링 하는 과정이 조금 바꼈다.
서브 쿼리를 통해 USED_GOODS_BOARD 에서 3건 이상 작성한 WRITER_ID 만 추출한 뒤, USED_GOODS_USER에서 그 ID들만 필터링하는 방식이다.
장/단점
- 장점
- 내부 GROUP BY가 먼저 실행되어 WRITER_ID만 뽑기 때문에, 외부 쿼리는 필요한 USER_ID만 조회한다. 즉, 중간 결과가 작아진다. (선필터 → 조회)
- USED_GOODS_USER에만 직접 접근하므로 JOIN 연산이 없다.
- IN 서브쿼리는 중복 제거 후 소수의 ID만 반환 → 인덱스 잘 타면 빠르다.
- 단점
- 서브쿼리 결과가 많이 나오면 IN 조건이 무거워질 수 있다 (하지만 여기선 3건 이상 게시글 작성자만 추리는 거라 크지 않음).
요약
WHERE IN 쿼리 | JOIN + GROUP BY 쿼리 | |
중간 결과 크기 | 작음 (필터된 ID만 추출) | 큼 (JOIN 후 GROUP BY 수행) |
JOIN 사용 | ❌ 없음 | ✅ 있음 |
쿼리 직관성 | ✅ 높음 | 조금 복잡함 |
인덱스 활용 | WRITER_ID 인덱스로 효율적 | WRITER_ID, USER_ID 조인 조건 필요 |
확장성 | 제한적 | ✅ 유연함 |
대용량 대응 | ✅ 더 유리 | 조건에 따라 느려질 수 있음 |
📌필자가 생각한 성능 비교
실제 데이터 양이 많지 않은 프로그래머스 환경에선 두 쿼리 모두 비슷한 성능을 보이지만, 실서비스나 대용량 환경이라면 2번 쿼리(WHERE IN 쿼리)가 더 안정적인 성능을 보일 가능성이 높다고 생각한다.
성능 최적화가 중요한 대용량 서비스에서는 불필요한 JOIN을 피하는 방향으로 설계하는 것이 유리하다고 생각하기 때문이다. (단 인덱스 필수)
따라서 만약 실무에서 해당 쿼리를 사용하는 상황이라면,
단순히 3개 이상 글 쓴 사용자 목록 조회 + 출력 최적화를 하고 싶다면 → 2번 쿼리를 사용하고,
더 복잡한 조건이 추가될 예정 (e.g. 카테고리별, 날짜별) 이라면 → 1번 쿼리를 더 확장해서 사용할 것 같다.
~ 끝 ~
오늘도 땡큐포와칭
'Algorithm > Programmers' 카테고리의 다른 글
[programmers lv.4] '보호소에서 중성화한 동물' MySQL 풀이 (0) | 2025.04.20 |
---|---|
[programmers lv.2 python] '석유 시추' 파이썬 풀이 (이제 시간초과를 곁들인 ..) (5) | 2024.12.13 |
[programmers lv1.python] 달리기 경주 풀이 (시간초과 해결) (1) | 2024.11.05 |
[programmers lv.1 python] '로또의 최저 순위와 최고 순위' 풀이 (2) | 2024.09.28 |
[programmers lv.1 python] 없는 숫자 더하기 (0) | 2024.08.12 |