DB 쿼리 로그, 운영에서 정말 필요할까?
운영 환경에서 DB 쿼리 로그를 어디까지 남겨야 하는지, 도움이 되는 순간과 조심해야 할 지점을 함께 정리한 글입니다.
운영 이슈를 몇 번 겪고 나면 한 번쯤 드는 생각이 있습니다.
"애초에 SQL 로그만 제대로 봤어도 빨리 찾았을 텐데"라는 생각입니다.
실제로 저도 그런 순간이 있었습니다.
응답 시간은 분명히 느린데 애플리케이션 로그만 봐서는 이유가 잘 안 보이고, 결국 마지막에 가서 쿼리 쪽을 의심하게 되는 경우였습니다.
그래서 처음에는 운영에서도 DB 쿼리 로그를 늘 켜두는 게 맞는 줄 알았습니다.
하지만 조금 지나고 나니 그 생각도 단순했다는 걸 알게 됐습니다.
정리하면 답은 이렇습니다.
운영에서 DB 쿼리 로그는 분명 필요할 때가 있다. 다만 항상 모든 쿼리를 그대로 남기는 방식이 정답은 아니다.
처음에는 "있으면 무조건 좋다"고 생각했다
개발 환경에서는 SQL 로그가 정말 편합니다.
- N+1 문제를 바로 볼 수 있고
- 어떤 조건으로 조회가 나갔는지 확인하기 쉽고
- 예상과 다른 업데이트 쿼리도 바로 찾을 수 있습니다
그래서 운영에서도 똑같이 켜두면 다 해결될 것처럼 느껴질 수 있습니다.
그런데 운영은 개발 환경과 조금 다릅니다.
- 트래픽이 훨씬 많고
- 로그 양도 훨씬 많고
- 쿼리 파라미터 안에 민감한 값이 섞일 수 있고
- 장애 상황에서는 오히려 로그가 너무 많아 읽기 어려워질 수 있습니다
결국 운영에서는 "많이 남기면 좋다"보다 어떤 상황에서 무엇을 볼 것인가를 먼저 정하는 편이 훨씬 중요했습니다.
그래도 쿼리 로그가 필요한 순간은 분명했다
운영에서 DB 쿼리 로그가 특히 도움이 됐던 경우는 아래와 같았습니다.
- N+1처럼 예상보다 쿼리 수가 갑자기 많아질 때
- 특정 API만 유독 느릴 때
- 배포 이후 쿼리 패턴이 달라졌는지 확인할 때
- 읽기 쿼리인지 쓰기 쿼리인지부터 구분이 안 될 때
예를 들어 API 응답 시간이 늘었는데 애플리케이션 코드만 봐서는 이유가 안 보이는 상황이 있습니다.
이럴 때 쿼리 로그를 보면,
- 같은 쿼리가 몇 번 반복되는지
- 조인이 갑자기 늘었는지
- 인덱스를 못 타는 조건이 추가됐는지
- 쿼리 자체는 빠른데 호출 횟수가 많은지
같은 힌트를 생각보다 빨리 얻을 수 있었습니다.
문제는 "항상 전체 쿼리를 남기기"가 부담스럽다는 점이었다
운영에서 전체 SQL과 바인딩 파라미터를 계속 남기면 생각보다 비용이 큽니다.
가장 먼저 체감되는 건 로그 양입니다.
- 요청 수가 많은 서비스에서는 로그가 너무 빨리 쌓이고
- 장애 상황에서는 필요한 로그보다 SQL 로그가 더 많이 보이고
- 저장/전송 비용도 무시하기 어렵습니다
여기에 민감 정보 문제도 있습니다.
사용자 식별자, 이메일, 검색어, 주소처럼 값이 파라미터에 들어가는 경우가 있기 때문입니다.
개발 환경에서는 편한 로그가, 운영에서는 그대로 남기기 부담스러운 데이터가 될 수 있습니다.
그래서 운영에서 "전체 쿼리 로그를 상시 활성화"하는 건 꽤 조심스럽게 봐야 한다고 느꼈습니다.
제가 더 자주 쓰게 된 건 슬로우 쿼리 관점이었다
운영에서는 전체 쿼리를 모두 보는 것보다, 느린 쿼리를 우선 보는 방식이 훨씬 실용적이었습니다.
예를 들면:
- 300ms 이상 걸린 쿼리만 남기기
- 500ms 이상만 따로 모니터링하기
- 특정 API 구간에서만 일시적으로 SQL 로그를 켜기
이런 방식입니다.
이 접근이 좋았던 이유는 명확했습니다.
- 로그 양이 훨씬 줄어든다
- 실제로 봐야 할 후보가 빨리 모인다
- 운영 이슈와 직접 연결되는 데이터만 먼저 볼 수 있다
결국 운영에서는 "모든 SQL을 다 안다"보다 "느린 이유를 빨리 찾는다"가 더 중요했습니다.
애플리케이션 로그와 따로 놀면 효과가 반감됐다
쿼리 로그가 있어도 애플리케이션 요청 로그와 연결되지 않으면 생각보다 답답했습니다.
예를 들어 어떤 SQL이 느렸다는 건 보이는데,
- 어떤 API 요청에서 나온 건지
- 어느 사용자의 요청인지
- 같은 요청 안에서 몇 번째 호출인지
를 모르면 다시 앞뒤를 추적해야 합니다.
그래서 운영에서 쿼리 로그를 본다면 traceId나 요청 단위 식별자와 같이 묶여 보이는 구조가 훨씬 좋았습니다.
SQL 그 자체보다, 어떤 요청 흐름에서 나온 SQL인지가 더 중요할 때가 많았기 때문입니다.
JPA를 쓴다면 더더욱 쿼리 로그가 유용할 때가 있다
JPA를 쓰면 코드만 봐서는 실제 SQL이 잘 안 드러나는 순간이 있습니다.
예를 들어 아래처럼 평범한 코드도:
orders.stream()
.map(order -> order.getMember().getName())
.toList();실제로는 추가 조회를 계속 만들 수 있습니다.
이런 문제는 운영에서 바로 전체 SQL을 다 남기지 않더라도, 문제가 의심되는 구간에서 쿼리 로그를 잠깐 보는 것만으로도 큰 도움이 됐습니다.
특히:
- fetch join이 빠졌는지
- batch size가 제대로 먹고 있는지
- 컬렉션 접근 때문에 추가 조회가 터지는지
같은 건 SQL을 직접 보는 게 제일 빨랐습니다.
결국 항상 켜기보다 "켜는 기준"을 만드는 편이 낫다고 느꼈다
지금은 운영에서 DB 쿼리 로그를 볼 때 아래 기준을 먼저 생각합니다.
- 상시로 남길 것인가, 진단 시점에만 켤 것인가
- 전체 SQL이 필요한가, 슬로우 쿼리만 보면 되는가
- 바인딩 파라미터를 그대로 남겨도 되는가
- 요청 로그와 같이 묶어 볼 수 있는가
이 기준이 없으면 로그는 남는데 정작 읽기가 어려워집니다.
제가 지금 선호하는 방식
운영에서는 아래 조합을 더 선호하게 됐습니다.
- 평소에는 애플리케이션 로그 + 요청 시간 + 에러 로그 중심
- DB 쪽은 슬로우 쿼리 로그나 APM으로 먼저 본다
- 특정 문제를 의심할 때만 SQL 로그를 좁은 범위로 켠다
- 민감한 파라미터는 그대로 노출하지 않도록 주의한다
이 방식은 화려하진 않지만 현실적이었습니다.
늘 모든 걸 다 보고 있는 건 아니지만, 문제가 생겼을 때 어디를 열어봐야 하는지는 분명해졌습니다.
그래서 결론은
DB 쿼리 로그는 운영에서 분명 필요합니다.
특히 느린 원인을 찾거나, 예상하지 못한 조회 패턴을 확인할 때는 꽤 강한 힌트를 줍니다.
다만 "운영이니까 항상 전체 SQL을 다 남겨야 한다"는 쪽에는 점점 거리를 두게 됐습니다.
그보다는 로그 양, 민감 정보, 추적 편의성을 같이 보면서 필요한 수준으로 켜는 방식이 더 낫다고 느끼고 있습니다.
운영 로그는 결국 많이 남기는 것보다, 필요한 순간에 바로 읽을 수 있어야 의미가 있었습니다.
DB 쿼리 로그도 마찬가지였습니다.