DB

[PostgreSQL] 사용자 키값으로 max+1 할때, 성능이슈가 있을 경우 해결방법 (자리수 제한이 있을때): 호텔 빈방찾기

현재 사용중인 쿼리가 속도 문제가 있다. 누가 개발한 쿼리인지 모르겠지만…. 뭔가 난잡해보인다. 참고로 실제 테이블과 컬럼은 아니다, 모두 임으로 변경하였다.

SELECT LPAD(MIN(A.USER_DEVICE_ID + 1)::VARCHAR, 5, '0') AS NEXT_USER_DEVICE_ID
FROM (
	SELECT USER_DEVICE_ID::INT4 AS USER_DEVICE_ID
	FROM TB_USER
	WHERE COMPANY_NO = #{compNo}
	AND COALESCE(DEL_YN, 'N') = 'N'
	UNION ALL
	SELECT 0
) A LEFT JOIN (
	SELECT USER_DEVICE_ID::INT4 AS USER_DEVICE_ID
	FROM TB_USER
	WHERE COMPANY_NO = #{compNo}
	AND COALESCE(DEL_YN, 'N') = 'N'
) B
ON A.USER_DEVICE_ID::INT4 + 1 = B.USER_DEVICE_ID::INT4
WHERE B.USER_DEVICE_ID IS NULL	

속도문제가 있고, 데이터가 쌓이면 언제가는 db가 터질 수도 있는 상황이라 개선이 필요하다.

그래서 아래처럼 변경하였다.

SELECT LPAD(COALESCE(
	(SELECT MIN(USER_DEVICE_ID::INT4 + 1)::VARCHAR
	 FROM TB_USER
	 WHERE COMPANY_NO = #{compNo}
	 AND COALESCE(DEL_YN, 'N') = 'N'
	 AND USER_DEVICE_ID::INT4 + 1 NOT IN (
		 SELECT USER_DEVICE_ID::INT4
		 FROM TB_USER
		 WHERE COMPANY_NO = #{compNo}
		 AND COALESCE(DEL_YN, 'N') = 'N'
	 )), '1'), 5, '0') AS NEXT_USER_DEVICE_ID;

위 쿼리도 나중에 데이터가 많아지면 NOT IN절이 문제가 될 수 있어서 아래 쿼리로 변경되었다.


SELECT LPAD(COALESCE(
	(SELECT MIN(USER_DEVICE_ID::INT4 + 1)::VARCHAR
	 FROM TB_USER t1
	 WHERE COMPANY_NO = #{compNo}
	 AND COALESCE(DEL_YN, 'N') = 'N'
	 AND NOT EXISTS (
		 SELECT 1
		 FROM TB_USER t2
		 WHERE t2.COMPANY_NO = #{compNo}
		 AND COALESCE(t2.DEL_YN, 'N') = 'N'
		 AND t2.USER_DEVICE_ID::INT4 = t1.USER_DEVICE_ID::INT4 + 1
	 )), '1'), 5, '0') AS NEXT_USER_DEVICE_ID;

하지만 위 쿼리도 최종적으로는 데이터가 쌓이면 쿼리튜닝이 추가적으로 필요해진다.

쿼리를 변경작업하면서 알게된 사실 하나는 max+1 이 무제한이 아니라 1번 부터 99999까지만 가능한 상태이고, 중간에 빈 자리가 생기면 그 값을 찾아서 사용해야하는 것이다.

개발이 누락된거네??

가만히 생각해보면 “호텔 빈방 찾기”와 유사한 내용이다.

아래 쿼리로 한방에 핸결된다.

SELECT LPAD(TEXT(A),5, '0') AS NEXT_USER_DEVICE_ID
FROM GENERATE_SERIES(1,99999) AS A
WHERE LPAD(TEXT(A),5,'0') NOT IN (
	  SELECT USER_DEVICE_ID FROM TB_USER
	  WHERE COMPANY_NO = #{compNo}
	  AND COALESCE (DEL_YN, 'N') = 'N')
LIMIT 1

1~99999 중에 비어 있는 곳이 있으면 제일 작은 숫자부터 리턴해준다.

error: Content is protected !!