IT
공통 쿼리 재사용을 고려한 랜덤 추출 쿼리 작성 방법 (Oracle + MyBatis)
꽥꽥꽥
2025. 3. 23. 21:50
최근 프로젝트에서 조건에 맞는 카테고리 중 랜덤으로 하나씩 상품을 뽑고, 조건에 맞는 나머지 상품을 추가로 추출하여 총 n개를 만드는 쿼리를 작성할 일이 있었다.
단순히, union all 로 처리할 수 있지만, 중복 상품, 조건 필터링, MyBatis와의 연동 등을 고려하다 보니 쿼리가 점점 길어졌다.
이 글에서는 Oracle에서 중복을 피하면서 효율적인 쿼리를 작성하고, MyBatis XML에서 공통 쿼리를 재활용하는 방법을 소개한다.
처음 작성한 쿼리
처음에 간단하게 각각 하나씩 뽑고 UNION ALL 로 붙이면 될 줄 알았다.
하지만 이 방식은 조건에 맞는 데이터를 추출하면서 쿼리 중복과 중복된 결과 처리 문제가 발생했다.
반복되는 UNION ALL 쿼리를 효율적으로 관리하고, MyBatis에서 공통 SQL을 재사용하는 방법을 정리해봤다.
SELECT prd_no FROM (
SELECT prd_no FROM A WHERE category = 1 AND category_code = '01' ORDER BY DBMS_RANDOM.RANDOM
) WHERE ROWNUM = 1
UNION ALL
... (category 2, 3, 4)
문제 상황
불편한 점
- prd_no 중복 발생 시 정확한 카운트 문제
- 중복 쿼리 반복 -> 가독성 저하
- 유지보수 어려움
- MyBatis 에서 동일 SQL 을 2~3번 반복 사용함
해결: 공통 SQL 분리 (<sql> 재사용)
같은 로직을 3번 박복하는 대신, <sql> 로 분리하여 한 번만 작성하고 재사용하니 훨씬 깔끔하고 유지보수도 쉬워졌다.
Oracle
WITH sample AS (
-- 중복된 부분 미리 정의
)
SELECT DISTINCT prd_no FROM sample
UNION ALL ...
MyBatis
<sql id="sample">
-- 카테고리별 랜덤 추출
</sql>
<select id="getPrdNoList" resultType="Long">
SELECT DISTINCT prd_no FROM (
<include refid="sample"/>
UNION ALL
SELECT prd_no FROM ...
)
</select>
배운 점 / 팁 정리
- Oracle 에선 WITH, MyBatis 에선 <sql> + <include> 조합을 활용하자.
- 중복된 prd_no 가 생길 수 있으니, DISTINCT, NOT IN 으로 필터링
- n개를 맞추려면 실제 뽑힌 상품 개수를 기준으로 계산해야 함
- 쿼리가 복잡해질수록 공통 쿼리 분리 습관이 필요하다.