DB정규화 문제
레거시 코드로 되어있는 DB 정규화
일부 오래된 잘못된 db로 설계된 케이스가 있다. 컬럼명이 lot1, lot2 ~ lot30까지 있으며 이 컬럼명하고 대비되는 컬럼이 wt1,wt2.... wt30 이런방식으로 되어 있다. 이런 코드는 하나의 데이터를 추가할 때마다 컬럼이 30개씩 발생한다. 이걸 어떻게 고치면 좋을까 고민이 필요하다.
개념
방식은 간단하다 다음과 같이 lot로 지정되어 있는 부분을 행으로 내리는 것이다 문제는 기존에 사용자가 동작하는 방식에서 영향을 주지 않거나 반대로 영향을 주는 부분을 모두 찾아 문제없이 고칠 수 있어야한다는 것이다.
확인사항
기존 코드 형태
코드는 다음과 데이터를 하나의 행으로 결과를 조회한다음. 해당행에 있는 데이터를 순차적으로 화면의 데이터에 넣는 방식을 택하고 있다.
사용하는 쿼리 확인
SELECT, INSERT, UPDATE 등의 쿼리에서 사용했다.
결정사항
DB정규화 작업을 진행하였다.
추가 결정사항
- 기존에 SELECT 하는 부분은 수정없이 쿼리에서도 동일하게 하나의 행으로 데이터를 전달하기 => 쿼리,DB 단만 작업
- JOIN 해서 중첩되는 쿼리 여러줄로 내려가기
1번 방식
SELECT문
SELECT 문에 대한 변경은 다음과 같이 MAX를 사용하였다. 원래 단일항목을 가져오는 쿼리여서 MAX(CASE WHEN ~) 방식을 사용해도 크게 문제가 없을 것으로 보인다.
SELECT
T.KEY1, T.KEY2, T.KEY3, T.TOTAL_COLUMN1,
MAX(CASE WHEN D.STEP_NO = 1 THEN D.DETAIL_COLUMN1 END) AS DETAIL_COLUMN1_1,
MAX(CASE WHEN D.STEP_NO = 2 THEN D.DETAIL_COLUMN1 END) AS DETAIL_COLUMN1_2,
MAX(CASE WHEN D.STEP_NO = 3 THEN D.DETAIL_COLUMN1 END) AS DETAIL_COLUMN1_3,
MAX(CASE WHEN D.STEP_NO = 1 THEN D.DETAIL_COLUMN2 END) AS DETAIL_COLUMN2_1,
MAX(CASE WHEN D.STEP_NO = 2 THEN D.DETAIL_COLUMN2 END) AS DETAIL_COLUMN2_2,
MAX(CASE WHEN D.STEP_NO = 3 THEN D.DETAIL_COLUMN2 END) AS DETAIL_COLUMN2_3
FROM TB_TOTAL_DATA T
LEFT JOIN TB_DETAIL_DATA D
ON T.KEY1 = D.KEY1
AND T.KEY2 = D.KEY2
AND T.KEY3 = D.KEY3
GROUP BY T.KEY1, T.KEY2, T.KEY3, T.TOTAL_COLUMN1;
UPDATE문
UPDATE문은 2번 하는방식으로 변경해야하며 반복문을 사용해서 여러번 I/O가 일어난다. 30건이나되니 생각보다 부하가 크다. / 기존에는 무조건 등록하면 UPDATE를 했지만 이렇게되면 화면단에서 변경된 데이터를 골라서 UPDATE하는 것이 낫다. 또한 하나의 TRANSACTION으로 업데이트하며 DB UPDATE순서를 정해서 LOCK걸리는걸 방지해야한다.
UPDATE TB_TOTAL_DATA
SET
TOTAL_COLUMN1 = 'UpdatedValue'
WHERE KEY1 = 'A' AND KEY2 = 'B' AND KEY3 = 'C';
UPDATE TB_DETAIL_DATA
SET
DETAIL_COLUMN1 = 'Detail1',
DETAIL_COLUMN2 = 'Detail3'
WHERE KEY1 = 'A' AND KEY2 = 'B' AND KEY3 = 'C' AND STEP_NO = 1;
UPDATE TB_DETAIL_DATA
SET
DETAIL_COLUMN1 = 'Detail2',
DETAIL_COLUMN2 = 'Detail4'
WHERE KEY1 = 'A' AND KEY2 = 'B' AND KEY3 = 'C' AND STEP_NO = 2;
2번 방식
여러행으로 나와서 화면단 JAVA단에서 넘겨주는 데이터가 ARRAY 형태이다.
SELECT
T.KEY1, T.KEY2, T.KEY3, T.TOTAL_COLUMN1,
D.STEP_NO, D.DETAIL_COLUMN1, D.DETAIL_COLUMN2
FROM TB_TOTAL_DATA T
JOIN TB_DETAIL_DATA D
ON T.KEY1 = D.KEY1
AND T.KEY2 = D.KEY2
AND T.KEY3 = D.KEY3
ORDER BY T.KEY1, T.KEY2, T.KEY3, D.STEP_NO;
회고
나는 결국 1번으로 작업하였다. 조회성 쿼리가 많고 UPDATE 하는 부분은 단일로 되어 있어서 JAVA부분을 건들이는건 많지 않았다. 남이 작성한 코드를 고친다는건 상당히 고된 일이다. 이미 돌아가고 있는 시스템을 개선하는 작업은 혹여나 에러가 걸릴까봐 더 조심스럽다. 하지만 방치하다보면 더 고치기 어려워지는 코드가 될 뿐이다.
반면에 여러가지를 신경써야하는 부분과 달리 단일행 UPDATE로 모든게 업데이트 되는 쿼리가 과연 나쁠까란 생각도 한번정도 해봤다. 물론 한번에 UPDATE한다는건 여러곳에서 UPDATE하면 동시성 제어 문제가 있지만 반대로 DB LOCK의 위험도 없고 내부코드도 간단하다. 중요로직아님 && 새로운 데이터 추가가 빈번하지 않음 && 종합데이터와 개별데이터간에 같이 조회 변경하는 연관성이 강하다면 하나의 테이블로 관리하는 것도 나쁘지 않다는 생각이 들었다.