베베개발자
성능 튜닝 삽질기 - 조회 1분 걸리던 화면을 10~15초까지 줄이기 본문
일을 하다 보면 자주 요청 오는 것 중에 하나가 성능 튜닝이다.
조회 화면이 많은 제품이다 보니 데이터가 쌓일수록 조회 속도가 느려지고, 유지보수 사이트에서는 조회 메뉴의 성능 개선 요청이 자주 들어온다.
보통은 회사 소속 성능튜닝 담당자가 현장에 방문해 힌트를 적용하거나, 고객사 DBA가 튜닝한 SQL을 전달해 주면 해당 SQL을 제품에 적용한 뒤 조회 결과가 기존과 동일한지, 데이터에 문제가 없는지만 확인하는 경우가 대부분이었다.
하지만 이번에 담당한 사이트는 이미 성능 튜닝 담당자가 방문한 상태였지만, 5개의 메뉴가 평균 20~30초 심한 경우 1분 이상 걸리는 상태였다.
결국 다시 튜닝 요청이 들어왔고 이번에는 직접 튜닝을 하게 되었다.
첫 튜닝 시도
사실 SQL 튜닝을 제대로 해본 적이 없었다. 그래서 우선 내가 할 수 있는 것 부터 시도해 보기로 했다.
| 1. 실행 계획을 분석하면서 AI와 함께 튜닝 방향을 검토 2. select 문에서 불필요하게 *로 되어있는 부분 정확하게 컬럼명시하기 |
필요하지 않은 컬럼까지 모두 조회하는 것도 성능에 영향을 주는 요인 중에 하나라고 하여, 필요한 컬럼만 조회하도록 수정하였다.
또한 실행 계획을 기반으로 AI에게 튜닝 방향을 물어보며, AI가 제안한 JOIN 순서 변경이나 조건 변경 등을 실제로 적용하여 비교해 보았다.
하지만 AI가 알려준 방식이 항상 더 빠른 것은 아니였다.
오히려 기존보다 느린 부분도 존재해서 수정한 쿼리와 기존 쿼리를 옵션으로 분리하여 현장에서 직접 비교할 수 있도록 구현하였다.
그리고 어느 부분에서 시간이 오래 걸리는지 확인하기 위해 제품에서 구현해 둔 실행 시간 측정 메서드를 이용해서 SQL이 수행되는 메서드의 실행 시간을 로그로 남겼다.
1차로 패치 진행 결과 기존보다는 속도가 빨라지기는 했지만 고객이 체감할 정도의 성능 개선이 아니어서 재 튜닝 요청이 들어왔다.
그래서 오랫동안 해당 제품을 담당했던 수석님께서 도움요청을 드렸다.
가장 먼저 이야기하신 부분이 불필요한 join이었다.
불필요한 JOIN도 옵티마이저의 처리 비용을 증가시키기 때문에 제거할 수 있는 부분부터 확인해 보라고 하셨다.
2차 튜닝 시도 - Join 절
화면에서 실제 사용하는 데이터가 무엇인지 다시 확인한 뒤 필요하지 않은 join과 컬럼들을 하나씩 제거했다.
화면 조회와 Excel 다운로드에서 동일한 메서드를 사용하는 부분들이 있어서 해당 부분을 분리하여 적용하였다.
그 결과 5개의 메뉴 중 일반 조회화면 3개는 성능이 눈에 띄게 개선되었다.
기존에는 20~30초 정도 걸리던 화면이 30건 정도 데이터를 조회해도 약 3초 이내로 나왔으며. 더 많은 데이터를 조회한 경우에도 약 5초 정도로 줄었다.
하지만 2개의 메뉴는 아직도 속도가 개선되지 않았다.
한 메뉴는 조회 화면처럼 보이지만 내부에서는 데이터를 삭제하고 다시 적재한 뒤 UPDATE까지 수행하는 등 40개가 넘는 로직을 수행하고 있었고,
다른 하나는 승인 화면으로 SELECT, INSERT, UPDATE, DELETE가 모두 발생하지만 SQL만 튜닝해서 해결할 수 있는 문제가 아니라 로직 자체를 변경이 필요한 단계였다.
반면 조회 화면은 SELECT 구문을 조금 더 개선할 여지가 있어 다시 튜닝을 진행하였다.
3차 튜닝 시도 - 조건 재 확인 및 Join 수정
튜닝 경험이 많은 분들에게 도움을 요청하였고, 여러 가지 조언을 들을 수 있었다.
가장 먼저 들었던 이야기는 조회의 시작이 되는 테이블의 데이터 양을 최대한 줄여야 한다는 것이었다.
인덱스를 활용할 수 있는 조건인데 빠져 있는 것은 없는지, 조금이라도 데이터를 더 줄일 수 있는 조건은 없는지를 다시 확인하였다.
그리고 서브쿼리도 가능한 경우에는 JOIN으로 변경하는 것이 좋다는 조언을 받아 적용하였다.
물론 모든 서브쿼리를 JOIN으로 바꾼 것은 아니지만, 변경 가능한 부분은 하나씩 수정하면서 비교해 보았다.
마지막으로는 해당 사이트 버전에는 Java 소스에서 SQL 문자열을 직접 조합하는 방식이었다.
예를 들어 신청 유형에 따라서
if(param == 1){
pstm.append(" where id1= 222")
}else{
pstm.append(" where id1= 333")
}
과 같이 서로 다른 SQL이 생성되고 있었다.
튜닝을 도와주신 분께서는 옵티마이저가 실행 계획을 재사용할 수 있도록 SQL 형태를 최대한 동일하게 유지하는 것이 좋다고 조언해 주셨다.
그래서 리터럴 값을 직접 사용하는 대신 바인드 변수(?)를 사용하는 방식으로 수정하였다.
해당 방식으로 약 6,283건의 데이터를 조회·가공하는 화면 속도가 기존 60초에서 25초로 나오도록 수정하였다.
하지만 고객은 이전부터 모든 화면이 3초 이내에 조회되기를 강하게 요청하고 있었다.
해당 부분을 수석님, 다른 분들과 논의한 결과 해당 로직 및 승인로직은 쿼리 튜닝만으로는 3초 이내로 만드는 것은 현실적으로 어렵다는 결론이 나왔다.
그래서 파트장님이 직접 고객사를 방문하여 해당 두 메뉴는 로직 자체를 변경하지 않는 이상 요구 성능을 만족하기 어렵다는 점을 설명하였다.
이후에도 전체 수행 시간은 약 25초였지만, 로그를 확인해 보니 그중 특정 SELECT가 각각 약 11초와 4초를 차지하고 있는 부분이 존재하여 회사 소속 튜닝 담당자에게 현장 튜닝을 요청하였다.
힌트절을 적용한 결과 해당 SELECT는 각각 약 0.5초와 1.4초까지 줄었고, 전체 수행 시간도 개발계 기준 약 10~15초 수준으로 개선되었다.
성능튜닝 어려운 그것...
이번 튜닝을 하면서 가장 크게 느낀 것은 SQL 자체보다 "병목을 찾는 과정"이 더 중요하다는 점이었다.
처음에는 실행 계획도 제대로 볼 줄 몰랐고, AI가 알려준 SQL을 적용하면 빨라질 것이라고 생각했다.
하지만 실제로는 AI가 제안한 SQL이 더 느려지는 경우도 있었고, 힌트절 하나로 해결되는 문제도 아니었다.
결국 중요한 것은 병목이 어디서 발생하는지 찾고, 불필요한 JOIN을 제거하고, 조건을 다시 확인하고, 실행 시간을 직접 측정하면서 하나씩 줄여나가는 과정이라는 것을 많이 배울 수 있었다.
아직 운영계에서 최종 성능은 확인하지 못했지만, 다음에 비슷한 성능 이슈가 발생한다면 이번보다 훨씬 빠르게 원인을 찾을 수 있을 것 같다.
그리고 아마 이다음은 이제 로직 자체 수정을 하게 되지 않을까라는 생각도 든다.
'회사회고록' 카테고리의 다른 글
| 성능 튜닝 삽질기 (2) - 20초에서 5초 이내로 쿼리 튜닝 (0) | 2026.07.15 |
|---|---|
| 운영계에서만 발생한 NullPointerException - 데이터 타입의 중요성 (0) | 2026.07.02 |
| 전수 테스트 중 서버 멈춤 현상 해결- DB connection close (0) | 2026.04.03 |
| 전수 테스트를 위한 데이터 마이그레이션 (0) | 2026.04.02 |
| @SessionAttributes 제거 일지(4) - 운영 적용 및 결과 (0) | 2026.03.24 |
