SELECT A.CH_TYPE_NM , A.ITEM_CD , IO_DATE = dbo.DTRIM(A.IO_DATE, '-') , CH_DATE , B.ITEM_NM , B.ITEM_SPEC , B.UNIT FROM ( SELECT DIV_CD , CH_TYPE , CH_TYPE_NM = '등록' , ITEM_CD , IO_DATE , CH_DATE FROM ( SELECT TOP 1 * FROM BZ990T_HIST WHERE (@iIO_NO = '' OR IO_NO = @iIO_NO) AND (@iIO_SEQ IS NULL OR IO_SEQ = @iIO_SEQ) AND (@iDIV_CD = '' OR DIV_CD = @iDIV_CD) AND ((@iIO_DATE_FROM = '' OR IO_DATE >= @iIO_DATE_FROM) AND (@iIO_DATE_TO = '' OR IO_DATE <= @iIO_DATE_TO)) ORDER BY CH_DATE ASC ) AS A WHERE CH_TYPE = 'A' UNION ALL SELECT DIV_CD , CH_TYPE , CH_TYPE_NM = '수정' , ITEM_CD , IO_DATE , CH_DATE FROM ( SELECT * FROM BZ990T_HIST A WHERE (@iIO_NO = '' OR IO_NO = @iIO_NO) AND (@iIO_SEQ IS NULL OR IO_SEQ = @iIO_SEQ) AND (@iDIV_CD = '' OR DIV_CD = @iDIV_CD) AND ((@iIO_DATE_FROM = '' OR IO_DATE >= @iIO_DATE_FROM) AND (@iIO_DATE_TO = '' OR IO_DATE <= @iIO_DATE_TO)) AND CH_SEQ <> (SELECT TOP 1 CH_SEQ FROM BZ990T_HIST B WHERE B.IO_NO = A.IO_NO AND B.IO_SEQ = A.IO_SEQ AND B.CH_TYPE = 'A' ORDER BY B.CH_DATE ASC) ) AS A WHERE CH_TYPE = 'A' UNION ALL SELECT DIV_CD , CH_TYPE , CH_TYPE_NM = '삭제' , ITEM_CD , IO_DATE , CH_DATE FROM ( SELECT TOP 1 * FROM BZ990T_HIST WHERE (@iIO_NO = '' OR IO_NO = @iIO_NO) AND (@iIO_SEQ IS NULL OR IO_SEQ = @iIO_SEQ) AND (@iDIV_CD = '' OR DIV_CD = @iDIV_CD) AND ((@iIO_DATE_FROM = '' OR IO_DATE >= @iIO_DATE_FROM) AND (@iIO_DATE_TO = '' OR IO_DATE <= @iIO_DATE_TO)) ORDER BY CH_DATE DESC ) AS A WHERE CH_TYPE = 'D' ) AS A JOIN BC200T B ON A.ITEM_CD = B.ITEM_CD ORDER BY A.CH_DATE
안녕하세요. SQL을 사용하여 개발을 시작한지 1년이 안된 개발자입니다.
해당 프로시저의 목적은 히스토리를 조회하는 단순한 역할입니다. 특정 행의 데이터가 등록/수정/삭제 되었는지 판단 해야하는데 수정하는 프로세스가 단순 수정이 아니라 '삭제->등록'과 같이 이루어지다 보니 히스토리 상에서 해당 내용을 판단하려다 보니 이렇게 내용이 길어지게 되었네요....
현재 히스토리에 약 40만 건의 데이터가 있고 조회 조건을 통해서 한 번에 약 10 - 20개 정도의 데이터를 조회하게 됩니다. 시간이 약 5-10초 정도 소요되어서 시간을 줄일 수 있는 방법이 없을까 하고 질문하게 되었습니다.
조언 부탁드립니다. 감사합니다.
등록/수정/삭제를 판별하는 기준이 이상합니다.
왜 이렇게 하는 걸까요?
현재 히스토리 테이블에 등록/삭제를 판단하는 기준은 존재하지만 수정은 따로 없고, '삭제 후 재등록'과 같은 프로세스로 진행됩니다.
그래서 해당 IO_NO, IO_SEQ로 등록된 ROW 중에 가장 첫번째 등록이 진짜 등록, 그 이후에 생긴 등록은 '수정' 이라고 판별하게 되었습니다.
구조가 이상하지만 우선은 이 상황 안에서 해결해야 하기에 방법을 찾고 있는 중입니다.
그건 입력 조건이 입력되엇을 때의 얘기인 것 같습니다.
지금 쿼리는 조건이 있을 때와 없을 때를 아우르는 쿼리네요?
조건이 없을 때는 어찌 판별하나요? 똑같이 판별하면 안될 것 같은데요?
조건이 없을 때의 조건도 상이하네요?
= '' 조건과 IS NULL 조건이 각각 다르게 쓰이네요?
이 조건들이 쓰임새가 있는 조건인지?
조건이 입력되지 않는 경우가 있는것인지?
원본테이블에 데이터 조건 걸어 조회시 데이터는 몇건이 나오나요?
간단한 예시 자료 보여주실 수 있는지요?
원본 대비 결과표.
네 맞습니다. 조건이 있을 때와 없을 때 모두 아우르는데 생각해보니 클라이언트에서 해당 조건이 입력되지 않을 경우는 없을 것 같네요.
추가로 IS NULL을 사용한 것은 @iIO_SEQ 값이 numeric이라서 이렇게 넣었는데 여기도 NULL일 경우는 없을 것 같아요.
혹시 조건이 없는 경우는 없다고 가정하고 해당 쿼리를 수정했을 때 추가로 개선해야 할 부분이 있을까요?
현재 원본테이블에는 총 32만건의 데이터가 있고 조건을 걸었을 때에는 약 11건 정도의 데이터가 나옵니다.
예를들어,
SELECT * FROM HISTORY
WHERE IO_NO = 'IO124124124' AND IO_SEQ = 11 이렇게요.
제가 잘 답변했는지 모르겠네요...ㅎㅎㅎ
SELECT div_cd
, ch_type
, CASE WHEN ch_type = 'D' THEN '삭제'
WHEN ch_type = 'A' AND rn = 1 THEN '등록'
WHEN ch_type = 'A' AND rn > 1 THEN '수정'
END ch_type_nm
, item_cd
, io_date
, ch_date
FROM (SELECT div_cd
, ch_type
, item_cd
, io_date
, ch_date
, ROW_NUMBER() OVER(PARTITION BY div_cd, io_no, io_seq, ch_type ORDER BY ch_date) rn
FROM bz990t_hist
WHERE io_no = @iio_no
AND io_seq = @iio_seq
AND div_cd = @idiv_cd
AND io_date >= @iio_date_from
AND io_date <= @iio_date_to
AND ch_type IN ('A', 'D')
) a
;
제 쿼리를 보시고 해당 조건으로 파티션을 나누어서 ROW_NUMBER를 매겨야겠다고 생각하신 것은 혹시 어떤 근거로 그렇게 판단하신 것일까요? 공부를 하면 당연히 사용할 수 있는 정석적인 방법인가요?
1. 올려주신 쿼리는 의도와 다르게 잘못 작성된 쿼리라고 생각했습니다.
2. 쿼리 및 댓글을 통해 작성 의도를 파악하려고 했습니다.
3. 작성 의도를 파악하여 그에 맞는 쿼리를 작성했습니다. (정확하게 파악했는지는 미지수)
제 의도와는 맞았습니다. 감사합니다.
다만 이렇게 판단하게 되신 근거가 궁금했습니다. 감사합니다 마농님