노후 재무 시스템의 Oracle 11g를 MySQL 8로 전환하며 SQL 문법·데이터 의미·옵티마이저·트랜잭션 동작의 미묘한 차이를 하나씩 해결한 경험담이다. ORM이 아닌 순수 SQL 기준으로 타입부터 격리 수준까지 짚는다.
핵심 포인트- DATE를 DATE·DATETIME, NUMBER를 BIGINT·DECIMAL, CLOB을 TEXT로 세분화하고, sequence는 AUTO_INCREMENT·별도 채번 테이블, ROWNUM은 LIMIT·ROW_NUMBER, (+) outer join은 ANSI JOIN·UNION, MERGE는 ON DUPLICATE KEY UPDATE, CONNECT BY는 WITH RECURSIVE로 재작성
- Oracle이 빈 문자열을 NULL로 저장하는 차이로 MyBatis dynamic WHERE가 빠져 전체 DELETE가 실행된 사고를 복구하고, NULLIF·CONCAT_WS·조건 재작성으로 재발 방지
- 5억 건 다중 JOIN 쿼리의 timeout을 날짜 partitioning으로 사례별 약 382배 개선하고, 제한적 index hint·OR을 UNION ALL 분리·TEMPTABLE view 풀기로 성능 확보
- Oracle 기본 READ COMMITTED에 맞춘 긴 트랜잭션이 MySQL 기본 REPEATABLE READ에서 lock 경합·장애를 일으켜 격리 수준을 조정 — 넉넉한 일정·상시 복구 backup·연계 모듈까지 의심하는 QA를 원칙으로 제시
왜 읽나Oracle에서 MySQL로 이관하며 문법 변환뿐 아니라 NULL 의미·옵티마이저·격리 수준 같은 함정을 미리 알고 싶은 DB 마이그레이션 담당자에게.